package ch.zhaw.gartenverwaltung.io;

import ch.zhaw.gartenverwaltung.types.Crop;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class JsonGardenPlanTest {
    private GardenPlan testDatabase;
    private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    /**
     * Files to isolate the test-units
     */
    private final URL dbDataSource = this.getClass().getResource("user-crops.json");
    private final URL testFile = this.getClass().getResource("test-user-crops.json");

    @BeforeEach
    void connectToDb() throws URISyntaxException, IOException {
        assertNotNull(testFile);
        assertNotNull(dbDataSource);
        Files.copy(Path.of(testFile.toURI()), Path.of(dbDataSource.toURI()), StandardCopyOption.REPLACE_EXISTING);
        testDatabase = new JsonGardenPlan(dbDataSource);
    }


    @Test
    @DisplayName("Check if results are retrieved completely.")
    void getCropsNotEmpty() {
        List<Crop> testList;
        try {
            testList = testDatabase.getCrops();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Assertions.assertEquals(3, testList.size());

        List<Long> plantIds = testList.stream().map(Crop::getPlantId).collect(Collectors.toList());
        List<Long> expected = Arrays.asList(1L, 1L, 0L);
        Assertions.assertEquals(expected, plantIds);
    }

    @Test
    @DisplayName("Check whether single access works.")
    void getCropById() throws IOException {
        Optional<Crop> testCrop = testDatabase.getCropById(1);
        assertTrue(testCrop.isPresent());
        Assertions.assertEquals(1, testCrop.get().getPlantId());
    }


    @Test
    @DisplayName("Check for a nonexisting crop.")
    void getCropByIdMustFail() throws IOException {
        Optional<Crop> testCrop = testDatabase.getCropById(99);
        Assertions.assertFalse(testCrop.isPresent());
    }

    @Test
    @DisplayName("Add new Crop.")
    void addNewCrop() {
        Crop crop = new Crop(3L, LocalDate.parse("2023-02-22", formatter));
        try {
            testDatabase.saveCrop(crop);
            assertTrue(crop.getCropId().isPresent());
            Optional<Crop> testCrop = testDatabase.getCropById(crop.getCropId().get());

            assertTrue(testCrop.isPresent());
            Assertions.assertEquals(crop, testCrop.get());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Test
    @DisplayName("Remove crop")
    void removeCrop(){
        try {
            Optional<Crop> crop = testDatabase.getCropById(2L);
            Assertions.assertTrue(crop.isPresent());
            testDatabase.removeCrop(crop.get());
            crop = testDatabase.getCropById(2L);
            Assertions.assertFalse(crop.isPresent());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

