package oving6.office;

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

public class PrinterTest {

	private Clerk clerk1;
	private Clerk clerk2;
	private Printer printer;

	@BeforeEach
	public void setUp() {
		printer = new Printer();
		clerk1 = new Clerk(printer);
		clerk2 = new Clerk(printer);
	}

	@Test
	@DisplayName("Testing printing")
	public void testPrintDocument() {
		assertThrows(IllegalArgumentException.class, () -> {
			printer.printDocument(null, clerk1);
		}, "Test that an exception is thrown when the document is null");

		assertThrows(IllegalArgumentException.class, () -> {
			printer.printDocument("document1", null);
		}, "Test that an exception is thrown when the worker is null");
	}

	@Test
	@DisplayName("Only one printer printing")
	public void testPrintSingleClerk() {
		assertEquals(0, printer.getPrintHistory(clerk1).size(),
				"Test initialization of the number of prints in the printer history");

		printer.printDocument("document1", clerk1);
		assertEquals(1, printer.getPrintHistory(clerk1).size(),
				"Test the number of prints in the history after 1 print");
		assertTrue(printer.getPrintHistory(clerk1).contains("document1"),
				"Test that the document that was printed is in the history");

		printer.printDocument("document2", clerk1);
		assertEquals(2, printer.getPrintHistory(clerk1).size(),
				"Test the number of prints in the history after 2 prints");
		assertTrue(printer.getPrintHistory(clerk1).contains("document2"),
				"Test that document 2 that was printed is in the history");
	}

	@Test
	@DisplayName("Multiple printers printing")
	public void testPrintMultipleClerks() {
		assertEquals(0, printer.getPrintHistory(clerk1).size(),
				"Test initialization of printer history for worker1");
		assertEquals(0, printer.getPrintHistory(clerk2).size(),
				"Test initialization of printer history for worker2");

		// Print document for Clerk 1
		printer.printDocument("document1", clerk1);
		assertEquals(1, printer.getPrintHistory(clerk1).size(),
				"Test the number of prints in the history for worker1 after printing 1 document");
		assertTrue(printer.getPrintHistory(clerk1).contains("document1"),
				"Test that the history of worker1 contains the document that was printed");
		assertEquals(0, printer.getPrintHistory(clerk2).size(),
				"Test the number of prints in the history for worker2 after worker1 has printed "
						+ "a document");

		// Print document for Clerk 2
		printer.printDocument("document2", clerk2);
		assertEquals(1, printer.getPrintHistory(clerk2).size(),
				"Test the number of prints in the history for worker2 after printing a document");
		assertTrue(printer.getPrintHistory(clerk2).contains("document2"),
				"Test that the history of worker2 contains the document that was printed");
		assertEquals(1, printer.getPrintHistory(clerk1).size(),
				"Test the number of prints in the history for worker1 after both worker1 and "
						+ "worker2 have printed 1 document each");
	}

	@Test
	@DisplayName("Modifying printer history is not allowed")
	public void testPrintHistoryModification() {
		printer.printDocument("document1", clerk1);
		printer.printDocument("document2", clerk1);
		assertEquals(2, printer.getPrintHistory(clerk1).size(),
				"Test the number of prints in the history after 2 prints");

		// Remove a document and check that the printer history remains unchanged
		printer.getPrintHistory(clerk1).remove("document1");
		assertEquals(2, printer.getPrintHistory(clerk1).size(),
				"Test the number of prints in the history after 2 prints and attempting to "
						+ "remove 1 of them");
	}
}
