package oving5;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

public class BinaryComputingIteratorTest {

	private Iterator<Double> iterator1;
	private Iterator<Double> iterator2;
	private Iterator<Double> iteratorShort;

	@BeforeEach
	public void setUp() {
		iterator1 = List.of(0.5, -2.0).iterator();
		iterator2 = List.of(5.0, 3.0).iterator();
		iteratorShort = List.of(5.0).iterator();
	}

	@Test
	@DisplayName("Check that the constructor sets up the iterator correctly")
	public void testConstructor() {
		assertThrows(IllegalArgumentException.class, () -> {
			new BinaryComputingIterator(null, iterator2, (a, b) -> a * b);
		}, "Iterator1 cannot be null");

		assertThrows(IllegalArgumentException.class, () -> {
			new BinaryComputingIterator(iterator1, null, (a, b) -> a * b);
		}, "Iterator2 cannot be null");

		assertThrows(IllegalArgumentException.class, () -> {
			new BinaryComputingIterator(iterator1, iterator2, null);
		}, "Operator cannot be null");
	}

	@Test
	@DisplayName("Check BinaryComputingIterator with multiplication")
	public void testMultiplication() {
		BinaryComputingIterator binaryIt =
				new BinaryComputingIterator(iterator1, iterator2, (a, b) -> a * b);
		assertEquals(2.5, binaryIt.next(), "The first number was incorrect");
		assertTrue(binaryIt.hasNext());
		assertEquals(-6.0, binaryIt.next(), "The second number was incorrect");
		assertFalse(binaryIt.hasNext());
	}

	@Test
	@DisplayName("Check BinaryComputingIterator with addition")
	public void testAddition() {
		BinaryComputingIterator binaryIt =
				new BinaryComputingIterator(iterator1, iterator2, (a, b) -> a + b);
		assertEquals(5.5, binaryIt.next(), "The first number was incorrect");
		assertTrue(binaryIt.hasNext());
		assertEquals(1.0, binaryIt.next(), "The second number was incorrect");
		assertFalse(binaryIt.hasNext());
	}

	@Test
	@DisplayName("Test multiplication with only one number")
	public void testShortIterator() {
		BinaryComputingIterator binaryIt =
				new BinaryComputingIterator(iterator1, iteratorShort, (a, b) -> a * b);
		assertEquals(2.5, binaryIt.next(), "The first number was incorrect");
		assertFalse(binaryIt.hasNext());
	}

	@Test
	@DisplayName("Test with default value, both a number and null")
	public void testShortIteratorAndDefault() {
		BinaryComputingIterator binaryIt =
				new BinaryComputingIterator(iterator1, iteratorShort, null, 2.0, (a, b) -> a * b);
		assertEquals(2.5, binaryIt.next(), "The first number was incorrect");
		assertTrue(binaryIt.hasNext());
		assertEquals(-4.0, binaryIt.next(), "The second number was incorrect");
		assertFalse(binaryIt.hasNext());
	}

	@Test
	@DisplayName("Test with an empty iterator")
	public void testEmptyIterator() {
		BinaryComputingIterator binaryIt = new BinaryComputingIterator(Collections.emptyIterator(),
				Collections.emptyIterator(), (a, b) -> a * b);
		assertFalse(binaryIt.hasNext(), "An empty iterator should not have next");
	}

	@Test
	@DisplayName("Test an empty iterator with default value")
	public void testEmptyIteratorAndDefault() {
		BinaryComputingIterator binaryIt = new BinaryComputingIterator(Collections.emptyIterator(),
				Collections.emptyIterator(), 1.0, 2.0, (a, b) -> a * b);
		assertFalse(binaryIt.hasNext(), "An empty iterator should not have next");
	}
}
