package com.iqser.red.persistence.service.v1.external.api.impl.controller;

import com.iqser.red.service.persistence.management.v1.processor.entity.migration.SaasMigrationStatusEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotFoundException;
import com.iqser.red.service.persistence.management.v1.processor.migration.SaasMigrationService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.SaasMigrationStatusPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.external.resource.MigrationStatusResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.SaasMigrationStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.saas.migration.MigrationStatusResponse;

import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.experimental.FieldDefaults;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

import static com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.SaasMigrationStatus.*;

@RestController
@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)
@RequiredArgsConstructor
public class MigrationStatusController implements MigrationStatusResource {

    SaasMigrationService saasMigrationService;

    SaasMigrationStatusPersistenceService saasMigrationStatusPersistenceService;

    FileStatusService fileStatusService;


    public MigrationStatusResponse migrationStatus() {

        int numberOfFilesToMigrate = saasMigrationStatusPersistenceService.countAll();

        Map<SaasMigrationStatus, Integer> filesInStatus = new HashMap<>();
        filesInStatus.put(MIGRATION_REQUIRED, saasMigrationStatusPersistenceService.countByStatus(MIGRATION_REQUIRED));
        filesInStatus.put(DOCUMENT_FILES_MIGRATED, saasMigrationStatusPersistenceService.countByStatus(DOCUMENT_FILES_MIGRATED));
        filesInStatus.put(REDACTION_LOGS_MIGRATED, saasMigrationStatusPersistenceService.countByStatus(REDACTION_LOGS_MIGRATED));
        filesInStatus.put(ANNOTATION_IDS_MIGRATED, saasMigrationStatusPersistenceService.countByStatus(ANNOTATION_IDS_MIGRATED));
        filesInStatus.put(FINISHED, saasMigrationStatusPersistenceService.countByStatus(FINISHED));
        filesInStatus.put(ERROR, saasMigrationStatusPersistenceService.countByStatus(ERROR));

        var filesInErrorState = saasMigrationStatusPersistenceService.findAllByStatus(ERROR);

        var errorCauses = filesInErrorState.stream()
                .collect(Collectors.toMap(errorFile -> errorFile.getDossierId() + "/" + errorFile.getFileId(), SaasMigrationStatusEntity::getErrorCause));

        return MigrationStatusResponse.builder().numberOfFilesToMigrate(numberOfFilesToMigrate).filesInStatus(filesInStatus).errorCauses(errorCauses).build();
    }


    @Override
    public ResponseEntity<?> startMigrationForFile(String dossierId, String fileId) {

        if (!fileStatusService.fileExists(fileId)) {
            throw new NotFoundException(String.format("File with id %s does not exist", fileId));
        }

        saasMigrationService.startMigrationForFile(dossierId, fileId);

        return ResponseEntity.ok().build();
    }


    @Override
    public ResponseEntity<?> revertMigrationForFile(String dossierId, String fileId) {

        if (!fileStatusService.fileExists(fileId)) {
            throw new NotFoundException(String.format("File with id %s does not exist", fileId));
        }

        if (!saasMigrationStatusPersistenceService.findById(fileId).getStatus().equals(FINISHED)) {
            throw new BadRequestException(String.format("File with id %s is not migrated yet, can't revert.", fileId));
        }

        saasMigrationService.revertMigrationForFile(dossierId, fileId);

        return ResponseEntity.ok().build();
    }


    @Override
    public ResponseEntity<?> requeueErrorFiles() {

        MigrationStatusResponse migrationStatus = migrationStatus();
        if (!migrationIsFinished(migrationStatus)) {
            throw new BadRequestException("There are still files processing, please wait until migration has finished to retry!");
        }

        saasMigrationService.requeueErrorFiles();

        return ResponseEntity.ok().build();
    }


    private static boolean migrationIsFinished(MigrationStatusResponse migrationStatus) {

        return migrationStatus.getFilesInStatus().entrySet()
                .stream()
                .filter(e -> e.getValue() > 0)
                .allMatch(e -> e.getKey().equals(FINISHED) || e.getKey().equals(ERROR));
    }

}
