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

import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.READ_RULES;
import static com.iqser.red.service.persistence.management.v1.processor.roles.ActionRoles.WRITE_RULES;
import static com.iqser.red.service.persistence.management.v1.processor.service.FeignExceptionHandler.processFeignException;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
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.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.iqser.red.service.persistence.management.v1.processor.client.redactionservice.RedactionClient;
import com.iqser.red.service.persistence.management.v1.processor.exception.FileUploadException;
import com.iqser.red.service.persistence.management.v1.processor.exception.InvalidRulesException;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.AuditPersistenceService;
import com.iqser.red.service.persistence.management.v1.processor.service.persistence.RulesPersistenceService;
import com.iqser.red.service.persistence.service.v1.api.external.resource.RulesResource;
import com.iqser.red.service.persistence.service.v1.api.shared.model.AuditCategory;
import com.iqser.red.service.persistence.service.v1.api.shared.model.Rules;
import com.iqser.red.service.persistence.service.v1.api.shared.model.audit.AuditRequest;
import com.knecon.fforesight.keycloakcommons.security.KeycloakSecurity;

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

@Slf4j
@RestController
@RequiredArgsConstructor
public class RulesController implements RulesResource {

    private static final String DOWNLOAD_FILE_NAME = "rules.drl";

    private final RulesPersistenceService rulesPersistenceService;
    private final RedactionClient redactionServiceClient;
    private final AuditPersistenceService auditPersistenceService;


    @Override
    @PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
    public void upload(@RequestBody Rules rules) {

        try {
            redactionServiceClient.testRules(rules.getRules());
        } catch (FeignException e) {
            if (e.status() == HttpStatus.BAD_REQUEST.value()) {
                throw new InvalidRulesException("Rules could not be updated, validation check failed: " + e.getMessage());
            }
            throw processFeignException(e);
        }
        rulesPersistenceService.setRules(rules.getRules(), rules.getDossierTemplateId());

        auditPersistenceService.audit(AuditRequest.builder()
                .userId(KeycloakSecurity.getUserId())
                .objectId(rules.getDossierTemplateId())
                .category(AuditCategory.DOSSIER_TEMPLATE.name())
                .message("Rules have been updated")
                .build());
    }


    @Override
    @PreAuthorize("hasAuthority('" + READ_RULES + "')")
    public Rules download(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId) {

        return new Rules(rulesPersistenceService.getRules(dossierTemplateId).getValue(), dossierTemplateId);

    }


    @Override
    @PreAuthorize("hasAuthority('" + WRITE_RULES + "')")
    public void uploadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @RequestPart(name = "file") MultipartFile file) {

        try {
            upload(new Rules(new String(file.getBytes(), StandardCharsets.UTF_8), dossierTemplateId));
        } catch (IOException e) {
            throw new FileUploadException("Could not upload file.", e);
        }

    }


    @Override
    @PreAuthorize("hasAuthority('" + READ_RULES + "')")
    public ResponseEntity<?> downloadFile(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId) {

        byte[] data = download(dossierTemplateId).getRules().getBytes(StandardCharsets.UTF_8);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.TEXT_PLAIN);

        httpHeaders.add("Content-Disposition", "attachment; filename*=utf-8\"" + DOWNLOAD_FILE_NAME + "\"");
        InputStream is = new ByteArrayInputStream(data);

        return new ResponseEntity<>(new InputStreamResource(is), httpHeaders, HttpStatus.OK);

    }

}
