package library.step1;

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

import java.time.LocalDate;
import java.util.List;

import org.junit.jupiter.api.Test;

// Characterization tests: fijan lo que LibraryDesk hace HOY, antes de
// refactorizar. Los valores esperados se copiaron de la salida real del
// programa, aunque algo parezca raro. Son los mismos en todos los pasos.
class LibraryDeskTest {

    private final LibraryDesk desk = new LibraryDesk();

    private static Loan loan(String title, ItemKind kind, String due, String returned) {
        return new Loan(title, kind, LocalDate.parse(due), LocalDate.parse(returned));
    }

    private static final List<Loan> ALICE_LOANS = List.of(
            loan("Clean Code", ItemKind.BOOK, "2026-10-01", "2026-10-06"),
            loan("Matrix", ItemKind.DVD, "2026-10-03", "2026-10-04"),
            loan("SICP", ItemKind.BOOK, "2026-10-10", "2026-10-08"));

    @Test
    void studentStatement() {
        Member alice = new Member("alice", MemberType.STUDENT);
        String expected = """
                Multas de alice (STUDENT)
                  Clean Code           5 días  S/ 1.50
                  Matrix               1 días  S/ 0.00
                  SICP                 0 días  S/ 0.00
                Total: S/ 1.50
                """;
        assertEquals(expected, desk.statement(alice, ALICE_LOANS));
    }

    @Test
    void totalFineMatchesStatement() {
        Member alice = new Member("alice", MemberType.STUDENT);
        assertEquals(150, desk.totalFine(alice, ALICE_LOANS));
    }

    @Test
    void studentFineIsCappedPerLoan() {
        Member alice = new Member("alice", MemberType.STUDENT);
        List<Loan> loans = List.of(
                loan("Matrix", ItemKind.DVD, "2026-09-01", "2026-10-01"),
                loan("Clean Code", ItemKind.BOOK, "2026-09-01", "2026-09-05"));
        // 28 días cobrables de DVD serían S/ 28.00, pero el tope es S/ 10.00 por préstamo.
        assertEquals(1000 + 100, desk.totalFine(alice, loans));
    }

    @Test
    void teacherPaysOnlyForDvds() {
        Member carol = new Member("carol", MemberType.TEACHER);
        List<Loan> loans = List.of(
                loan("SICP", ItemKind.BOOK, "2026-10-01", "2026-10-11"),
                loan("Matrix", ItemKind.DVD, "2026-10-01", "2026-10-04"));
        assertEquals(300, desk.totalFine(carol, loans));
    }

    @Test
    void visitorPaysDoubleWithoutGrace() {
        Member bob = new Member("bob", MemberType.VISITOR);
        List<Loan> loans = List.of(
                loan("Clean Code", ItemKind.BOOK, "2026-10-01", "2026-10-05"),
                loan("Matrix", ItemKind.DVD, "2026-10-01", "2026-10-02"));
        assertEquals(400 + 200, desk.totalFine(bob, loans));
    }

    @Test
    void visitorStatementWithoutCap() {
        Member bob = new Member("bob", MemberType.VISITOR);
        List<Loan> loans = List.of(loan("Matrix", ItemKind.DVD, "2026-09-01", "2026-10-01"));
        String expected = """
                Multas de bob (VISITOR)
                  Matrix              30 días  S/ 60.00
                Total: S/ 60.00
                """;
        assertEquals(expected, desk.statement(bob, loans));
    }

    @Test
    void emptyStatement() {
        Member bob = new Member("bob", MemberType.VISITOR);
        assertEquals("Multas de bob (VISITOR)\nTotal: S/ 0.00\n", desk.statement(bob, List.of()));
    }
}
