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

import java.util.List;
import java.util.Optional;

import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.iqser.red.persistence.service.v1.external.api.impl.controller.DownloadController;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.ReportTemplateEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException;
import com.iqser.red.service.persistence.management.v1.processor.roles.ApplicationRoles;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DownloadStatusPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.users.UserService;
import com.iqser.red.service.persistence.management.v1.processor.service.users.model.User;
import com.iqser.red.service.persistence.service.v1.api.shared.model.RemoveDownloadRequest;
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadStatus;
import com.iqser.red.service.persistence.service.v2.api.external.model.DownloadStatusList;
import com.iqser.red.service.persistence.service.v2.api.external.resource.DownloadResource;
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;

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

@RestController
@RequiredArgsConstructor
@Tag(name = "5. Downloads", description = "Operations related to download packages.")
public class DownloadControllerV2 implements DownloadResource {

    private final DownloadController downloadController;
    private final DownloadStatusPersistenceService downloadStatusPersistenceService;
    private final UserService userService;


    @Transactional
    public DownloadStatusList getDownloadStatusList() {

        validateUserRoles(KeycloakSecurity.getUserId());
        var downloads = downloadStatusPersistenceService.getStatusesByUser(KeycloakSecurity.getUserId());

        return new DownloadStatusList(downloads.stream().map(
                status ->
                        DownloadStatus.builder()
                                .id(status.getUuid()) // This is a workaround the real id 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() != null ? status.getDossier().getId() : null)
                                .fileIds(status.getFiles()
                                                 .stream()
                                                 .map(FileEntity::getId)
                                                 .toList())
                                .downloadFileTypes(status.getDownloadFileTypes()
                                                           .stream()
                                                           .toList())
                                .reportTemplateIds(status.getReports().stream().map(ReportTemplateEntity::getTemplateId).toList())
                                .build()).toList()
        );
    }


    @Transactional
    public DownloadStatus getDownloadStatus(@PathVariable(DOWNLOAD_ID_PARAM) String downloadId) {

        validateUserRoles(KeycloakSecurity.getUserId());
        var status = downloadStatusPersistenceService.getStatusesByUuid(downloadId);

        return DownloadStatus.builder()
                .id(status.getUuid()) // This is a workaround the real id 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(status.getReports().stream().map(ReportTemplateEntity::getTemplateId).toList())
                .build();
    }


    public void deleteDownload(@PathVariable(DOWNLOAD_ID_PARAM) String downloadId) {

        validateUserRoles(KeycloakSecurity.getUserId());
        var status = downloadStatusPersistenceService.getStatusesByUuid(downloadId);
        downloadController.deleteDownloadStatus(new RemoveDownloadRequest(List.of(status.getStorageId())));
    }


    public void download(@PathVariable(DOWNLOAD_ID_PARAM) String downloadId) {

        validateUserRoles(KeycloakSecurity.getUserId());
        var status = downloadStatusPersistenceService.getStatusesByUuid(downloadId);
        downloadController.downloadFile(status.getStorageId());
    }


    private void validateUserRoles(String userId) {

        Optional<User> userOptional = userService.getUserById(userId);
        if (userOptional.isPresent()) {
            if (userOptional.get().getRoles()
                    .stream()
                    .noneMatch(ApplicationRoles.VALID_MEMBER_ROLES::contains)) {
                throw new NotAllowedException("User doesn't have appropriate roles");
            }
        }
    }

}
