package com.iqser.red.service.peristence.v1.server.integration.tests;

import static org.assertj.core.api.Assertions.assertThat;

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

import com.iqser.red.service.peristence.v1.server.integration.client.LicenseReportClient;
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTemplateTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.service.DossierTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.service.FileTesterAndProvider;
import com.iqser.red.service.peristence.v1.server.integration.utils.AbstractPersistenceServerServiceTest;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.DossierRepository;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.repository.FileRepository;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier;
import com.iqser.red.service.persistence.service.v1.api.shared.model.license.LicenseReport;
import com.iqser.red.service.persistence.service.v1.api.shared.model.license.LicenseReportRequest;

public class LicenseReportTest extends AbstractPersistenceServerServiceTest {

    @Autowired
    private DossierTemplateTesterAndProvider dossierTemplateTesterAndProvider;

    // No need for this warning here, since the test will fail if the client cannot be injected
    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    private LicenseReportClient licenseReportClient;

    @Autowired
    private FileTesterAndProvider fileTesterAndProvider;

    @Autowired
    private DossierTesterAndProvider dossierTesterAndProvider;

    @Autowired
    private FileRepository fileRepository;

    @Autowired
    private DossierRepository dossierRepository;


    @Test
    public void testLicenseReport() {

        var template = dossierTemplateTesterAndProvider.provideTestTemplate();

        var lastYearDossier = dossierTesterAndProvider.provideTestDossier(template, "lastYearDossier");
        var lastYearFile1 = addFileOnDate(lastYearDossier, "2022-01-01T10:00:00Z");
        var lastYearFile2 = addFileOnDate(lastYearDossier, "2022-01-02T10:00:00Z");

        var januaryDossier = dossierTesterAndProvider.provideTestDossier(template, "januaryDossier");
        var januaryFile1 = addFileOnDate(januaryDossier, "2023-01-01T10:00:00Z");
        var januaryFile2 = addFileOnDate(januaryDossier, "2023-01-02T10:00:00Z");

        var februaryDossier = dossierTesterAndProvider.provideTestDossier(template, "februaryDossier");
        var februaryFile1 = addFileOnDate(februaryDossier, "2023-02-01T10:00:00Z");
        var februaryFile2 = addFileOnDate(februaryDossier, "2023-02-02T10:00:00Z");

        var marchDossier = dossierTesterAndProvider.provideTestDossier(template, "marchDossier");
        var marchFile1 = addFileOnDate(marchDossier, "2023-03-01T10:00:00Z");
        var marchFile2 = addFileOnDate(marchDossier, "2023-03-02T10:00:00Z");

        var aprilDossier = dossierTesterAndProvider.provideTestDossier(template, "aprilDossier");
        var aprilFile1 = addFileOnDate(aprilDossier, "2023-04-01T10:00:00Z");
        var aprilFile2 = addFileOnDate(aprilDossier, "2023-04-02T10:00:00Z");

        softDeleteFile(januaryFile1.getFileId(), "2023-02-01T10:00:00Z");

        hardDeleteFile(januaryFile1.getFileId(), "2023-03-01T10:00:00Z");

        archiveDossier(februaryDossier.getDossierId(), "2023-05-01T10:00:00Z");

        LicenseReport licenseReport = licenseReportClient.getReport(LicenseReportRequest.builder()
                .startDate(Instant.parse("2023-01-01T10:00:00Z"))
                .endDate(Instant.parse("2023-05-01T11:00:00Z"))
                .build());

        assertThat(licenseReport.getTotalFilesUploadedBytes()).isEqualTo(900L);
        assertThat(licenseReport.getActiveFilesUploadedBytes()).isEqualTo(700L);
        assertThat(licenseReport.getArchivedFilesUploadedBytes()).isEqualTo(200L);
        assertThat(licenseReport.getTrashFilesUploadedBytes()).isEqualTo(0L);

        assertThat(licenseReport.getMonthlyData().size()).isEqualTo(5);
        assertThat(licenseReport.getMonthlyData().get(1).getTrashFilesUploadedBytes()).isEqualTo(100L);
        assertThat(licenseReport.getMonthlyData().get(2).getTrashFilesUploadedBytes()).isEqualTo(0L);
    }


    private FileStatus addFileOnDate(Dossier dossier, String date) {

        var file = fileTesterAndProvider.testAndProvideFile(dossier, date + ".pdf");
        setAdded(file.getId(), date);
        return file;
    }


    private void setAdded(String fileId, String date) {

        fileRepository.findById(fileId).ifPresent((file) -> {

            file.setAdded(OffsetDateTime.ofInstant(Instant.parse(date), ZoneId.of("Z")));
            file.setFileSize(100L);
            fileRepository.saveAndFlush(file);

        });
    }


    private void archiveDossier(String dossierId, String date) {

        dossierRepository.findById(dossierId).ifPresent((dossier) -> {
            dossier.setArchivedTime(OffsetDateTime.ofInstant(Instant.parse(date), ZoneId.of("Z")));
            dossierRepository.saveAndFlush(dossier);
        });
    }


    private void softDeleteFile(String fileId, String date) {

        fileRepository.findById(fileId).ifPresent((file) -> {
            file.setDeleted(OffsetDateTime.ofInstant(Instant.parse(date), ZoneId.of("Z")));
            fileRepository.saveAndFlush(file);
        });
    }


    private void hardDeleteFile(String fileId, String date) {

        fileRepository.findById(fileId).ifPresent((file) -> {
            file.setHardDeletedTime(OffsetDateTime.ofInstant(Instant.parse(date), ZoneId.of("Z")));
            fileRepository.saveAndFlush(file);
        });
    }

}
