package inventory;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import java.util.List;

/**
 * Unit tests for InventoryManager class.
 */
class InventoryManagerTest {

    private InventoryManager manager;

    /**
     * Set up fresh instance before each test
     */
    @BeforeEach
    void setUp() {
        manager = new InventoryManager();
    }

    /**
     * Test adding products to inventory
     */
    @Test
    void testAddProduct() {
        boolean succeeded = manager.addProduct("TEST1", "Test Book", "BOOK", 10.0, 1);
        assertTrue(succeeded);
        assertTrue(manager.productExists("TEST1"));
        assertEquals(10.00, manager.getInventoryValue());
    }

    /**
     *  Test adding product with invalid parameters
     */
    @Test
    void testAddInvalidProduct() {
        boolean succeeded = manager.addProduct("TEST1", "Test Book", "BOOK", 0, 1);
        assertFalse(succeeded);
        assertEquals(0, manager.getInventoryValue());
    }

    /**
     * Test selling products
     */
    @Test
    void testSellProduct() {
        manager.addProduct("TEST1", "Test Book", "BOOK", 10.0, 10);
        assertEquals(100.00, manager.getInventoryValue());

        manager.sellProduct("TEST1", 2, "NONE");
        assertEquals(80.00, manager.getInventoryValue());

        manager.sellProduct("TEST1", 6, "BULK");
        assertEquals(20.00, manager.getInventoryValue());

        manager.sellProduct("TEST1", 2, "STUDENT");
        assertEquals(0, manager.getInventoryValue());
    }

    /**
     * Test selling more than available stock
     */
    @Test
    void testSellInsufficientStock() {
        manager.addProduct("TEST1", "Test Book", "BOOK", 10.0, 10);
        assertEquals(100.00, manager.getInventoryValue());

        manager.sellProduct("TEST1", 12, "NONE");
        assertEquals(100.00, manager.getInventoryValue());
    }

    /**
     * Test adding stock to existing product
     */
    @Test
    void testAddStock() {
        manager.addProduct("TEST1", "Test Book", "BOOK", 10.0, 1);
        assertEquals(10.00, manager.getInventoryValue());

        manager.addStock("TEST1", 1);
        assertEquals(20.00, manager.getInventoryValue());
    }

    /**
     * Test inventory value calculation
     */
    @Test
    void testInventoryValue() {
        manager.addProduct("TEST1", "Test Book", "BOOK", 10.0, 2);
        manager.addProduct("TEST2", "Test Book", "BOOK", 50.0, 1);
        assertEquals(2 * 10.00 + 1 * 50.00, manager.getInventoryValue());
    }

    /**
     * Test low stock detection
     */
    @Test
    void testLowStockProducts() {
        manager.addProduct("TEST1", "Test Book", "BOOK", 10.0, 1);
        manager.addProduct("TEST2", "Test Book", "BOOK", 10.0, 2);
        manager.addProduct("TEST5", "Test Book", "BOOK", 10.0, 5);
        manager.addProduct("TEST10", "Test Book", "BOOK", 10.0, 10);

        List<Product> lowStockUnder5 = manager.getLowStockProducts(5);
        assertEquals(2, lowStockUnder5.size());
        assertTrue(lowStockUnder5.stream().anyMatch(p -> p.getId().equals("TEST1")));
        assertTrue(lowStockUnder5.stream().anyMatch(p -> p.getId().equals("TEST2")));
    }

    /**
     * Test operations on non-existent products
     */
    @Test
    void testNonExistentProduct() {
        boolean sellSucceeded = manager.sellProduct("NONE", 1, "BOOK");
        assertFalse(sellSucceeded);

        boolean addStockSucceeded = manager.addStock("NONE", 1);
        assertFalse(addStockSucceeded);
    }

    /**
     * Test complete workflow
     */
    @Test
    void testCompleteWorkflow() {

        boolean addSucceeded = manager.addProduct("TEST1", "Test Book", "BOOK", 10.0, 10);
        assertTrue(addSucceeded);
        assertEquals(100.00, manager.getInventoryValue());

        boolean addStockSucceeded = manager.addStock("TEST1", 10);
        assertTrue(addStockSucceeded);
        assertEquals(200.00, manager.getInventoryValue());

        boolean sellSucceeded = manager.sellProduct("TEST1", 18, "NONE");
        assertTrue(sellSucceeded);
        assertEquals(20.00, manager.getInventoryValue());
    }
}