import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;

class LoggingSongRepositoryTest {

    /** Fake: un repositorio en memoria que recuerda lo que se le guardó. */
    static class InMemoryRepository implements SongRepository {
        List<Song> stored = List.of();
        IOException failure = null;

        @Override
        public List<Song> load() throws IOException {
            if (failure != null) {
                throw failure;
            }
            return stored;
        }

        @Override
        public void save(List<Song> songs) {
            stored = List.copyOf(songs);
        }
    }

    private final List<String> log = new ArrayList<>();
    private final InMemoryRepository inner = new InMemoryRepository();
    private final SongRepository repo = new LoggingSongRepository(inner, log::add);

    @Test
    void saveDelegatesAndLogs() throws IOException {
        List<Song> songs = List.of(new Song("A", "B", 10));
        repo.save(songs);
        assertEquals(songs, inner.stored);
        assertEquals(List.of("save: 1 canciones"), log);
    }

    @Test
    void loadReturnsWhatTheInnerRepositoryReturns() throws IOException {
        inner.stored = List.of(new Song("A", "B", 10), new Song("C", "D", 20));
        assertSame(inner.stored, repo.load());
        assertEquals(List.of("load: 2 canciones"), log);
    }

    @Test
    void failuresAreLoggedAndRethrown() {
        IOException boom = new IOException("disco lleno");
        inner.failure = boom;
        assertSame(boom, assertThrows(IOException.class, repo::load));
        assertEquals(List.of("load falló: disco lleno"), log);
    }

    @Test
    void decoratorsCanBeStacked() throws IOException {
        List<String> outer = new ArrayList<>();
        SongRepository twice = new LoggingSongRepository(repo, outer::add);
        twice.save(List.of());
        assertEquals(List.of("save: 0 canciones"), log);
        assertEquals(List.of("save: 0 canciones"), outer);
    }
}
