package fabrik.simulator.pic16f84;

import fabrik.simulator.pic16f84.interfaces.CommandInterface;
import fabrik.simulator.pic16f84.interfaces.DataRegisterInterface;
import fabrik.simulator.pic16f84.interfaces.EEPROMInterface;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;


class EEPROMTests {
    PICComponentLocator picComponents;
    String savedEEPROM;

    public EEPROMTests() {}

    @BeforeEach
    void resetComponentsAndReadEEPROM() throws IOException {
        picComponents = new PICComponentLocator();
        savedEEPROM = Files.readString(Path.of("eeprom.json"));
    }

    @AfterEach
    public void rewriteEEPROM() throws IOException {
        FileWriter writer = new FileWriter("eeprom.json");
        writer.write(savedEEPROM);
        writer.close();
    }

    @Test
    @DisplayName("EEPROM read gibt gültigen Wert zurück")
    void eepromReadReturnsValidLong() throws IOException {
        FileWriter writer = new FileWriter("eeprom.json");
        writer.write("{\"0\": 255}");
        writer.close();

        DataRegisterInterface mockDataRegister = Mockito.mock(DataRegisterInterface.class);
        picComponents.registerComponent(DataRegisterInterface.class, mockDataRegister);

        EEPROMInterface eeprom = new EEPROM();
        picComponents.registerComponent(EEPROMInterface.class, eeprom);
        picComponents.initAll();


        long value = eeprom.read(0);


        assertEquals(255, value);
    }


    @Test
    @DisplayName("EEPROM write schreibt an die korrekte Adresse in eeprom.json")
    void eepromWritesCorrectly() throws IOException {
        FileWriter writer = new FileWriter("eeprom.json");
        writer.write("{}");
        writer.close();

        DataRegisterInterface mockDataRegister = Mockito.mock(DataRegisterInterface.class);
        picComponents.registerComponent(DataRegisterInterface.class, mockDataRegister);

        ExecutionTimeSubject mockExecutionTime = mock(ExecutionTimeSubject.class);
        picComponents.registerComponent(ExecutionTimeSubject.class, mockExecutionTime);

        EEPROMInterface eeprom = new EEPROM();
        picComponents.registerComponent(EEPROMInterface.class, eeprom);
        picComponents.initAll();


        eeprom.write(3, 123);


        assertEquals("{\"3\":123}", Files.readString(Path.of("eeprom.json")));
    }


    @Test
    @DisplayName("EEPROM write schreibt nicht an negative Adressen")
    void eepromDoesntWriteNegative() throws IOException {
        FileWriter writer = new FileWriter("eeprom.json");
        writer.write("{}");
        writer.close();

        DataRegisterInterface mockDataRegister = Mockito.mock(DataRegisterInterface.class);
        picComponents.registerComponent(DataRegisterInterface.class, mockDataRegister);

        CommandInterface mockCommands = mock(CommandInterface.class);
        picComponents.registerComponent(CommandInterface.class, mockCommands);

        EEPROMInterface eeprom = new EEPROM();
        picComponents.registerComponent(EEPROMInterface.class, eeprom);
        picComponents.initAll();


        eeprom.write(-1, 1);


        assertEquals("{}", Files.readString(Path.of("eeprom.json")));
    }


    @Test
    @DisplayName("EEPROM read mit negativem Wert liefert 0")
    void eepromReadWithNegativeAddress() throws IOException {
        FileWriter writer = new FileWriter("eeprom.json");
        writer.write("{\"-1\":5}");
        writer.close();

        DataRegisterInterface mockDataRegister = Mockito.mock(DataRegisterInterface.class);
        picComponents.registerComponent(DataRegisterInterface.class, mockDataRegister);

        CommandInterface mockCommands = mock(CommandInterface.class);
        picComponents.registerComponent(CommandInterface.class, mockCommands);

        EEPROMInterface eeprom = new EEPROM();
        picComponents.registerComponent(EEPROMInterface.class, eeprom);
        picComponents.initAll();


        long result = eeprom.read(-1);


        assertEquals(0, result);
    }
}