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

import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_DOSSIER_ATTRIBUTES;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_DOSSIER_ATTRIBUTES_CONFIG;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_DOSSIER_ATTRIBUTES;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_DOSSIER_ATTRIBUTES_CONFIG;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_FILE_ATTRIBUTES;

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

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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;
import com.iqser.red.service.persistence.management.v1.processor.entity.dossier.DossierAttributeConfigEntity;
import com.iqser.red.service.persistence.management.v1.processor.service.AccessControlService;
import com.iqser.red.service.persistence.management.v1.processor.service.DossierAttributesManagementService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.DossierAttributeConfigPersistenceService;
import com.knecon.fforesight.databasetenantcommons.providers.utils.MagicConverter;
import com.iqser.red.service.persistence.service.v1.api.external.resource.DossierAttributesResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierAttributes;
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierAttributesConfig;
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.DossierAttributeConfig;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.DossierAttribute;

import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
public class DossierAttributesController implements DossierAttributesResource {

    private final DossierAttributeConfigPersistenceService dossierAttributeConfigPersistenceService;
    private final AuditPersistenceService auditPersistenceService;
    private final DossierAttributesManagementService dossierAttributesManagementService;
    private final AccessControlService accessControlService;


    @Override
    @PreAuthorize("hasAuthority('" + WRITE_DOSSIER_ATTRIBUTES_CONFIG + "')")
    public DossierAttributesConfig setDossierAttributesConfig(String dossierTemplateId, DossierAttributesConfig dossierAttributesConfig) {

        var result = MagicConverter.convert(dossierAttributeConfigPersistenceService.setDossierAttributesConfig(dossierTemplateId,
                MagicConverter.convert(dossierAttributesConfig.getDossierAttributeConfigs(), DossierAttributeConfigEntity.class)), DossierAttributeConfig.class);
        auditPersistenceService.insertRecord(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierTemplateId)
                .category(AuditCategory.DOSSIER_TEMPLATE.name())
                .message("Changed dossier attributes base configuration.")
                .build());
        return new DossierAttributesConfig(result);

    }


    @Override
    @PreAuthorize("hasAuthority('" + WRITE_DOSSIER_ATTRIBUTES_CONFIG + "')")
    public DossierAttributeConfig addOrUpdateDossierAttributeConfig(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId,
                                                                    @RequestBody DossierAttributeConfig dossierAttribute) {

        var result = MagicConverter.convert(dossierAttributeConfigPersistenceService.addOrUpdateDossierAttribute(dossierTemplateId,
                MagicConverter.convert(dossierAttribute, DossierAttributeConfigEntity.class)), DossierAttributeConfig.class);
        auditPersistenceService.insertRecord(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierTemplateId)
                .category(AuditCategory.DOSSIER_TEMPLATE.name())
                .message("Dossier attributes added/updated")
                .build());

        return result;
    }


    @Override
    @PreAuthorize("hasAuthority('" + WRITE_DOSSIER_ATTRIBUTES_CONFIG + "')")
    public void deleteDossierAttributeConfig(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @PathVariable(DOSSIER_ATTRIBUTE_ID) String dossierAttributeId) {

        dossierAttributeConfigPersistenceService.deleteDossierAttribute(dossierAttributeId);
        auditPersistenceService.insertRecord(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierTemplateId)
                .category(AuditCategory.DOSSIER_TEMPLATE.name())
                .message("Dossier attributes removed")
                .details(Map.of("DossierAttributeId", dossierAttributeId))
                .build());
    }


    @Override
    @PreAuthorize("hasAuthority('" + WRITE_DOSSIER_ATTRIBUTES_CONFIG + "')")
    public void deleteDossierAttributesConfig(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId, @RequestParam(DOSSIER_ATTRIBUTE_IDS) List<String> dossierAttributeIds) {

        dossierAttributeConfigPersistenceService.deleteDossierAttributes(dossierAttributeIds);
        auditPersistenceService.insertRecord(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierTemplateId)
                .category(AuditCategory.DOSSIER_TEMPLATE.name())
                .message("Dossier attributes removed")
                .details(Map.of("DossierAttributeId", dossierAttributeIds))
                .build());
    }


    @PreAuthorize("hasAuthority('" + READ_DOSSIER_ATTRIBUTES_CONFIG + "')")
    public DossierAttributesConfig getDossierAttributesConfig(@PathVariable(DOSSIER_TEMPLATE_ID) String dossierTemplateId) {

        var result = dossierAttributeConfigPersistenceService.getDossierAttributes(dossierTemplateId);
        return new DossierAttributesConfig(MagicConverter.convert(result, DossierAttributeConfig.class));
    }


    @PreAuthorize("hasAuthority('" + WRITE_FILE_ATTRIBUTES + "')")
    public DossierAttributes setDossierAttributes(@PathVariable(DOSSIER_ID) String dossierId, @RequestBody DossierAttributes dossierAttributes) {

        accessControlService.verifyUserIsDossierOwner(dossierId);
        var result = dossierAttributesManagementService.setDossierAttributes(dossierId, dossierAttributes.getDossierAttributeList());
        auditPersistenceService.insertRecord(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierId)
                .category(AuditCategory.DOSSIER.name())
                .message("Changed dossier attributes.")
                .build());
        return new DossierAttributes(result);

    }


    @PreAuthorize("hasAuthority('" + WRITE_DOSSIER_ATTRIBUTES + "')")
    public DossierAttributes addOrUpdateDossierAttribute(String dossierId, DossierAttribute dossierAttribute) {

        accessControlService.verifyUserIsDossierOwner(dossierId);
        DossierAttribute result = dossierAttributesManagementService.addOrUpdateDossierAttribute(dossierId, dossierAttribute);
        auditPersistenceService.insertRecord(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierId)
                .category(AuditCategory.DOSSIER.name())
                .message("Added or updated dossier attributes.")
                .build());
        return new DossierAttributes(List.of(result)); // TODO should be single Object???
    }


    @PreAuthorize("hasAuthority('" + READ_DOSSIER_ATTRIBUTES + "')")
    public DossierAttributes getDossierAttributes(String dossierId) {

        var result = dossierAttributesManagementService.getDossierAttributes(dossierId);
        auditPersistenceService.insertRecord(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierId)
                .category(AuditCategory.DOSSIER.name())
                .message("Got dossier attributes.")
                .build());
        return new DossierAttributes(result);

    }


    @PreAuthorize("hasAuthority('" + WRITE_DOSSIER_ATTRIBUTES + "')")
    public void deleteDossierAttribute(String dossierId, String dossierAttributeId) {

        accessControlService.verifyUserIsDossierOwner(dossierId);
        dossierAttributesManagementService.deleteDossierAttribute(dossierId, dossierAttributeId);
        auditPersistenceService.insertRecord(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(dossierId)
                .category(AuditCategory.DOSSIER.name())
                .message("Changed dossier attributes.")
                .build());

    }

}
