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

import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierResource.DOSSIER_ID_PARAM;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierResource.INCLUDE_ACTIVE_PARAM;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierResource.INCLUDE_ARCHIVED_PARAM;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierResource.INCLUDE_SOFT_DELETED_PARAM;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource.DOSSIER_TEMPLATE_ID_PARAM;

import java.util.ArrayList;
import java.util.List;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierController;
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DossierTemplateController;
import com.iqser.red.persistence.service.v1.external.api.impl.controller.DownloadController;
import com.iqser.red.persistence.service.v1.external.api.impl.controller.FileAttributesController;
import com.iqser.red.persistence.service.v1.external.api.impl.controller.FileManagementController;
import com.iqser.red.persistence.service.v1.external.api.impl.controller.StatusController;
import com.iqser.red.persistence.service.v1.external.api.impl.controller.UploadController;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusManagementService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusMapper;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributes;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileUploadResult;
import com.iqser.red.service.persistence.service.v1.api.shared.model.PrepareDownloadWithOptionRequest;
import com.iqser.red.service.persistence.service.v2.api.external.model.BulkDownloadRequest;
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadRequest;
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadStatus;
import com.iqser.red.service.persistence.service.v2.api.external.model.FileDeleteRequest;
import com.iqser.red.service.persistence.service.v2.api.external.model.FileStatusList;
import com.iqser.red.service.persistence.service.v2.api.external.resource.FileResource;

import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@Tag(name = "3. File endpoints", description = "Provides operations related to files")
public class FileControllerV2 implements FileResource {

    private final UploadController uploadController;
    private final StatusController statusController;
    private final DossierController dossierController;
    private final FileManagementController fileManagementController;
    private final FileStatusManagementService fileStatusManagementService;
    private final FileAttributesController fileAttributesController;
    private final DossierTemplateController dossierTemplateController;
    private final DownloadController downloadController;
    private final DownloadStatusPersistenceService downloadStatusPersistenceService;


    public FileUploadResult upload(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                                   @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                                   @RequestPart(name = FILE_PARAM) MultipartFile file,
                                   @RequestParam(value = KEEP_MANUAL_CHANGES_PARAM, required = false, defaultValue = "false") boolean keepManualChanges,
                                   @RequestParam(value = DISABLE_AUTOMATIC_ANALYSIS_PARAM, required = false, defaultValue = "false") boolean disableAutomaticAnalysis) {

        dossierTemplateController.getDossierTemplate(dossierTemplateId);

        return uploadController.upload(file, dossierId, keepManualChanges, disableAutomaticAnalysis);
    }


    public FileStatusList getDossierStatus(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                                           @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                                           @RequestParam(name = INCLUDE_ACTIVE_PARAM, defaultValue = "true", required = false) boolean includeActive,
                                           @RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived,
                                           @RequestParam(name = INCLUDE_SOFT_DELETED_PARAM, defaultValue = "false", required = false) boolean includeSoftDeleted) {

        dossierTemplateController.getDossierTemplate(dossierTemplateId);
        dossierController.getDossier(dossierId, includeArchived, includeSoftDeleted);

        List<FileStatus> fileStatusList = new ArrayList<>();

        if (!includeArchived && dossierController.getDossier(dossierId, false, includeSoftDeleted).getArchivedTime() != null) {
            return new FileStatusList(fileStatusList);
        }

        if (includeActive) {
            fileStatusList.addAll(statusController.getDossierStatus(dossierId));
        }

        if (includeSoftDeleted) {
            fileStatusList.addAll(statusController.getSoftDeletedDossierStatus(dossierId));
        }

        return new FileStatusList(fileStatusList);
    }


    public FileStatus getFileStatus(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                                    @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                                    @PathVariable(FILE_ID_PARAM) String fileId,
                                    @RequestParam(name = INCLUDE_SOFT_DELETED_PARAM, defaultValue = "false", required = false) boolean includeSoftDeleted) {

        dossierTemplateController.getDossierTemplate(dossierTemplateId);

        dossierController.getDossier(dossierId, true, includeSoftDeleted);

        return FileStatusMapper.toFileStatus(fileStatusManagementService.getFileStatus(fileId, includeSoftDeleted));
    }


    public void deleteFile(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                           @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                           @PathVariable(FILE_ID_PARAM) String fileId,
                           @RequestParam(name = DELETE_PERMANENTLY_PARAM, defaultValue = "false", required = false) boolean deletePermanently) {

        dossierTemplateController.getDossierTemplate(dossierTemplateId);

        if (deletePermanently) {
            fileManagementController.hardDeleteFiles(dossierId, List.of(fileId));
        } else {
            fileManagementController.deleteFile(dossierId, fileId);
        }

    }


    public void deleteFiles(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                            @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                            @RequestBody FileDeleteRequest fileDeleteRequest,
                            @RequestParam(name = DELETE_PERMANENTLY_PARAM, defaultValue = "false", required = false) boolean deletePermanently) {

        dossierTemplateController.getDossierTemplate(dossierTemplateId);

        if (deletePermanently) {
            fileManagementController.hardDeleteFiles(dossierId, new ArrayList<>(fileDeleteRequest.getFileIds()));
        } else {
            fileManagementController.deleteFiles(dossierId, fileDeleteRequest.getFileIds());
        }
    }


    public void setFileAttributes(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                                  @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                                  @PathVariable(FILE_ID_PARAM) String fileId,
                                  @RequestBody FileAttributes fileAttributes) {

        dossierTemplateController.getDossierTemplate(dossierTemplateId);

        fileAttributesController.setFileAttributes(dossierId, fileId, fileAttributes);
    }


    public DownloadStatus prepareFileDownload(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                                              @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                                              @PathVariable(FILE_ID_PARAM) String fileId,
                                              @RequestBody DownloadRequest downloadRequest) {

        return prepareBulkDownload(dossierTemplateId,
                                   dossierId,
                                   BulkDownloadRequest.builder()
                                           .reportTemplateIds(downloadRequest.getReportTemplateIds())
                                           .downloadFileTypes(downloadRequest.getDownloadFileTypes())
                                           .redactionPreviewColor(downloadRequest.getRedactionPreviewColor())
                                           .fileIds(List.of(fileId))
                                           .build());
    }


    public DownloadStatus prepareBulkDownload(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                                              @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                                              @RequestBody BulkDownloadRequest bulkDownloadRequest) {

        dossierTemplateController.getDossierTemplate(dossierTemplateId);

        var storageId = downloadController.prepareDownload(PrepareDownloadWithOptionRequest.builder()
                                                                   .dossierId(dossierId)
                                                                   .fileIds(bulkDownloadRequest.getFileIds())
                                                                   .reportTemplateIds(bulkDownloadRequest.getReportTemplateIds())
                                                                   .downloadFileTypes(bulkDownloadRequest.getDownloadFileTypes())
                                                                   .redactionPreviewColor(bulkDownloadRequest.getRedactionPreviewColor())
                                                                   .includeUnprocessed(false)
                                                                   .build()).getStorageId();

        var status = downloadStatusPersistenceService.getStatus(storageId);

        return DownloadStatus.builder()
                .id(status.getUuid()) // This is a workaround the real is the storageId.
                .userId(status.getUserId())
                .filename(status.getFilename())
                .mimeType(status.getMimeType())
                .errorCause(status.getErrorCause())
                .status(status.getStatus())
                .creationDate(status.getCreationDate())
                .lastDownload(status.getLastDownload())
                .fileSize(status.getFileSize())
                .dossierId(status.getDossier().getId())
                .fileIds(status.getFiles()
                                 .stream()
                                 .map(FileEntity::getId)
                                 .toList())
                .downloadFileTypes(status.getDownloadFileTypes()
                                           .stream()
                                           .toList())
                .reportTemplateIds(bulkDownloadRequest.getReportTemplateIds())
                .build();
    }

}
