package oving7.savingsaccount;

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 BSUTest {

	private static final double epsilon = 0.001;

	private BSU bsu;

	@BeforeEach
	public void setUp() {
		bsu = new BSU(0.05, 25_000.0);
	}

	@Test
	@DisplayName("Check that deposits work as expected")
	public void testDeposit() {
		bsu.deposit(10_000.0);
		assertEquals(10_000.0, bsu.getBalance(), epsilon, "The account balance was incorrect");

		assertThrows(IllegalArgumentException.class, () -> {
			bsu.deposit(-100.0);
		}, "Negative deposit should have triggered an IllegalArgumentException!");

		assertThrows(IllegalStateException.class, () -> {
			bsu.deposit(20_000.0);
		}, "Should not be able to deposit more money than the deposit limit");

		bsu.endYearUpdate();
		bsu.deposit(20_000.0);
		assertEquals(10_000.0 * (1 + 0.05) + 20_000.0, bsu.getBalance(), epsilon,
				"The account balance was incorrect");
	}

	@Test
	@DisplayName("Check that withdrawals work as expected")
	public void testWithdraw() {
		bsu.deposit(20_000.0);
		bsu.withdraw(5000.0);
		assertEquals(15_000.0, bsu.getBalance(), epsilon, "The account balance was incorrect");

		assertThrows(IllegalArgumentException.class, () -> {
			bsu.withdraw(-10_000.0);
		}, "Negative withdrawal should have triggered an IllegalArgumentException!");

		assertEquals(15_000.0, bsu.getBalance(), epsilon, "The account balance was incorrect");

		assertThrows(IllegalStateException.class, () -> {
			bsu.withdraw(20_000);
		}, "Should not be able to withdraw more money than deposited this year");

		assertEquals(15_000.0, bsu.getBalance(), epsilon, "The account balance was incorrect");

		bsu.endYearUpdate();

		assertThrows(IllegalStateException.class, () -> {
			bsu.withdraw(10_000);
		}, "Should not be able to withdraw more money than deposited this year");

		assertEquals(15_000 * (1 + 0.05), bsu.getBalance(), epsilon,
				"The account balance was incorrect");
	}

	@Test
	@DisplayName("Check that the tax deduction is correct")
	public void testTaxDeduction() {
		bsu.deposit(20_000.0);
		assertEquals(20_000.0 * 0.20, bsu.getTaxDeduction(), epsilon,
				"The tax deduction was incorrect");

		bsu.endYearUpdate();
		bsu.deposit(10_000.0);
		assertEquals(10_000.0 * 0.20, bsu.getTaxDeduction(), epsilon,
				"The tax deduction was incorrect");

		bsu.endYearUpdate();
		assertEquals(0.0, bsu.getTaxDeduction(), epsilon, "The tax deduction was incorrect");
	}
}
