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

import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_FILE_ATTRIBUTES_CONFIG;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_FILE_ATTRIBUTES;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_FILE_ATTRIBUTES_CONFIG;

import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
import com.iqser.red.service.persistence.management.v1.processor.entity.configuration.FileAttributesGeneralConfigurationEntity;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.FileAttributeConfigEntity;
import com.iqser.red.service.persistence.management.v1.processor.exception.BadRequestException;
import com.iqser.red.service.persistence.management.v1.processor.exception.NotAllowedException;
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileAttributesManagementService;
import com.iqser.red.service.persistence.management.v1.processor.service.FileStatusService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.FileAttributeConfigPersistenceService;
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
import com.iqser.red.service.persistence.service.v1.api.external.resource.FileAttributesResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributes;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributesConfig;
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.FileAttributesGeneralConfiguration;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.FileAttributeConfig;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.file.WorkflowStatus;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
@RequiredArgsConstructor
public class FileAttributesController implements FileAttributesResource {

    private final FileAttributesManagementService fileAttributesManagementService;
    private final FileAttributeConfigPersistenceService fileAttributeConfigPersistenceService;
    private final AuditPersistenceService auditPersistenceService;
    private final FileStatusService fileStatusService;
    private final AccessControlService accessControlService;


    @Override
    @PreAuthorize("hasAuthority('" + WRITE_FILE_ATTRIBUTES_CONFIG + "')")
    public FileAttributesConfig setFileAttributesConfig(String dossierTemplateId, FileAttributesConfig fileAttributesConfig) {

        if (StringUtils.isEmpty(fileAttributesConfig.getEncoding()) || !encodingList.contains(fileAttributesConfig.getEncoding().trim())) {
            throw new BadRequestException("Invalid encoding setting");
        }
        fileAttributeConfigPersistenceService.setFileAttributesGeneralConfig(dossierTemplateId,
                MagicConverter.convert(fileAttributesConfig, FileAttributesGeneralConfigurationEntity.class));
        var result = fileAttributeConfigPersistenceService.setFileAttributesConfig(dossierTemplateId,
                MagicConverter.convert(fileAttributesConfig.getFileAttributeConfigs(), FileAttributeConfigEntity.class));
        auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierTemplateId)
                .category(AuditCategory.DOSSIER_TEMPLATE.name())
                .message("Changed file attributes base configuration & attribute configuration ( CSV Import )")
                .build());
        return FileAttributesConfig.builder()
                .filenameMappingColumnHeaderName(fileAttributesConfig.getFilenameMappingColumnHeaderName())
                .delimiter(fileAttributesConfig.getDelimiter())
                .encoding(fileAttributesConfig.getEncoding())
                .fileAttributeConfigs(MagicConverter.convert(result, FileAttributeConfig.class))
                .build();

    }


    @Override
    @PreAuthorize("hasAuthority('" + WRITE_FILE_ATTRIBUTES_CONFIG + "')")
    public FileAttributeConfig addOrUpdateFileAttribute(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @RequestBody FileAttributeConfig fileAttribute) {

        var result = fileAttributeConfigPersistenceService.addOrUpdateFileAttribute(dossierTemplateId, MagicConverter.convert(fileAttribute, FileAttributeConfigEntity.class));
        auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierTemplateId)
                .category(AuditCategory.DOSSIER_TEMPLATE.name())
                .message("File attributes added/updated")
                .details(Map.of("FileAttributeName", fileAttribute.getLabel() != null ? fileAttribute.getLabel() : "", "dossierTemplateId", dossierTemplateId))
                .build());

        return MagicConverter.convert(result, FileAttributeConfig.class);
    }


    @Override
    @PreAuthorize("hasAuthority('" + WRITE_FILE_ATTRIBUTES_CONFIG + "')")
    public void deleteFileAttribute(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @PathVariable(FILE_ATTRIBUTE_ID) String fileAttributeId) {

        fileAttributeConfigPersistenceService.deleteFileAttribute(fileAttributeId);
        auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierTemplateId)
                .category(AuditCategory.DOSSIER_TEMPLATE.name())
                .message("File attributes removed")
                .details(Map.of("FileAttributeId", fileAttributeId))
                .build());
    }


    @Override
    @PreAuthorize("hasAuthority('" + WRITE_FILE_ATTRIBUTES_CONFIG + "')")
    public void deleteFileAttributes(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @RequestBody List<String> fileAttributeIds) {

        fileAttributeConfigPersistenceService.deleteFileAttributes(fileAttributeIds);
        auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierTemplateId)
                .category(AuditCategory.DOSSIER_TEMPLATE.name())
                .message("File attributes removed")
                .details(Map.of("FileAttributeId", fileAttributeIds))
                .build());
    }


    @PreAuthorize("hasAuthority('" + READ_FILE_ATTRIBUTES_CONFIG + "')")
    public FileAttributesConfig getFileAttributesConfiguration(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId) {

        var fileAttributeConfigs = fileAttributeConfigPersistenceService.getFileAttributes(dossierTemplateId);
        FileAttributesGeneralConfiguration generalConfig = new FileAttributesGeneralConfiguration();
        try {
            generalConfig = MagicConverter.convert(fileAttributeConfigPersistenceService.getFileAttributesGeneralConfiguration(dossierTemplateId),
                    FileAttributesGeneralConfiguration.class);
        } catch (Exception e) {
            log.debug("No general config defined", e);
        }
        return FileAttributesConfig.builder()
                .filenameMappingColumnHeaderName(generalConfig.getFilenameMappingColumnHeaderName())
                .delimiter(generalConfig.getDelimiter())
                .encoding(generalConfig.getEncoding())
                .fileAttributeConfigs(MagicConverter.convert(fileAttributeConfigs, FileAttributeConfig.class))
                .build();
    }


    @PreAuthorize("hasAuthority('" + WRITE_FILE_ATTRIBUTES + "')")
    public void setFileAttributes(@PathVariable(DOSSIER_ID_PARAM) String dossierId, @PathVariable(FILE_ID) String fileId, @RequestBody FileAttributes fileAttributes) {

        var file = fileStatusService.getStatus(fileId);

        if (file.getWorkflowStatus().equals(WorkflowStatus.APPROVED)) {
            throw new NotAllowedException("File is approved. File attributes are not editable anymore.");
        }
        if (file.getWorkflowStatus().equals(WorkflowStatus.UNDER_APPROVAL)) {
            accessControlService.verifyUserIsApprover(dossierId);
        }
        accessControlService.verifyUserIsMemberOrApprover(dossierId);
        fileAttributesManagementService.setFileAttributes(dossierId, fileId, fileAttributes.getAttributeIdToValue());
        auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(fileId)
                .category(AuditCategory.DOCUMENT.name())
                .message("File attributes has been edited for a document.")
                .build());

    }

}
