package oving6.stock;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class StockTest {

	private Stock stock;
	private double oldPrice;
	private double newPrice;

	// Used to check that listeners work
	private double oldPriceListener;
	private double newPriceListener;

	private void setPriceForListener(double oldPrice, double newPrice) {
		oldPriceListener = oldPrice;
		newPriceListener = newPrice;
	}

	private void setPriceCheckListener(double newPrice, double expectedOldPrice,
			double expectedNewPrice) {
		// Update the price
		this.oldPrice = this.newPrice;
		this.newPrice = newPrice;
		stock.setPrice(newPrice);

		// Check that the listener has received the change
		assertEquals(expectedOldPrice, this.oldPriceListener,
				"Test old price for listener after updating price from " + oldPrice + " to "
						+ newPrice);
		assertEquals(expectedNewPrice, this.newPriceListener,
				"Test new price for listener after updating price from " + oldPrice + " to "
						+ newPrice);
	}

	@BeforeEach
	public void setUp() {
		stock = new Stock("APPL", 110.0);
		oldPrice = 0.0;
		newPrice = 110.0;
		oldPriceListener = 0.0;
		newPriceListener = 0.0;
	}

	@Test
	@DisplayName("Test constructor")
	public void testConstructor() {
		assertEquals("APPL", stock.getTicker(), "Test ticker");
		assertEquals(110.0, stock.getPrice(), "Test stock price");

		assertThrows(IllegalArgumentException.class, () -> {
			new Stock(null, 110.0);
		}, "Test constructor with null ticker");
	}

	@Test
	@DisplayName("Negative stock price throws error")
	public void testSetNegativePrice() {
		assertThrows(IllegalArgumentException.class, () -> {
			stock.setPrice(-20.0);
		}, "Test setting negative stock price");
	}

	@Test
	@DisplayName("Stock price equal to zero throws error")
	public void testSetZeroPrice() {
		assertThrows(IllegalArgumentException.class, () -> {
			stock.setPrice(0);
		}, "Test setting stock price equal to zero");
	}

	@Test
	@DisplayName("Add listener")
	public void testStockListener() {
		StockListener listener = (Stock stock, double oldPrice, double newPrice) -> this
				.setPriceForListener(oldPrice, newPrice);
		stock.addStockListener(listener);

		this.setPriceCheckListener(118.0, 110.0, 118.0);
		assertEquals(118.0, stock.getPrice(), "Test stock price after updating price");

		this.setPriceCheckListener(121.0, 118.0, 121.0);
		assertEquals(121.0, stock.getPrice(), "Test stock price after updating price twice");
	}
}
