import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import org.junit.jupiter.api.Test;

// Pruebas públicas de P1 para Product. No las modifiquen.
class P1ProductPublicTest {

    private static Product milk() {
        return new Product("LEC-01", "Leche evaporada", 420, 24);
    }

    @Test
    void rejectsBlankCode() {
        assertThrows(IllegalArgumentException.class, () -> new Product("  ", "Leche evaporada", 420, 24));
    }

    @Test
    void rejectsNullName() {
        assertThrows(IllegalArgumentException.class, () -> new Product("LEC-01", null, 420, 24));
    }

    @Test
    void rejectsZeroPrice() {
        assertThrows(IllegalArgumentException.class, () -> new Product("LEC-01", "Leche evaporada", 0, 24));
    }

    @Test
    void rejectsNegativeStock() {
        assertThrows(IllegalArgumentException.class, () -> new Product("LEC-01", "Leche evaporada", 420, -1));
    }

    @Test
    void acceptsZeroStock() {
        Product p = new Product("LEC-01", "Leche evaporada", 420, 0);

        assertEquals(0, p.stock());
    }

    @Test
    void rejectsNonPositiveQuantitiesAndKeepsTheStock() {
        Product p = milk();

        assertThrows(IllegalArgumentException.class, () -> p.addStock(0));
        assertThrows(IllegalArgumentException.class, () -> p.removeStock(-3));
        assertEquals(24, p.stock());
    }

    @Test
    void removingMoreThanTheStockFailsAndChangesNothing() {
        Product p = milk();

        assertThrows(IllegalStateException.class, () -> p.removeStock(25));
        assertEquals(24, p.stock());
    }

    @Test
    void removingTheWholeStockLeavesZero() {
        Product p = milk();

        p.removeStock(24);

        assertEquals(0, p.stock());
    }

    @Test
    void changePriceKeepsOnlyPositivePrices() {
        Product p = milk();

        p.changePrice(450);
        assertThrows(IllegalArgumentException.class, () -> p.changePrice(0));

        assertEquals(450, p.priceCents());
    }

    @Test
    void productsWithTheSameCodeAreEqual() {
        Product a = milk();
        Product b = new Product("LEC-01", "Leche evaporada light", 450, 3);

        assertEquals(a, b);
        assertEquals(a.hashCode(), b.hashCode());
    }

    @Test
    void productsWithDifferentCodesAreNotEqual() {
        Product a = milk();
        Product b = new Product("LEC-02", "Leche evaporada", 420, 24);

        assertNotEquals(a, b);
    }

    @Test
    void aProductIsNotEqualToNullOrToAString() {
        Product a = milk();

        assertFalse(a.equals(null));
        assertFalse(a.equals("LEC-01"));
    }

    @Test
    void toStringShowsCodeNamePriceAndStock() {
        Product p = new Product("ARR-02", "Arroz superior 5 kg", 2190, 8);

        assertEquals("ARR-02 Arroz superior 5 kg (S/ 21.90, stock 8)", p.toString());
    }
}
