package com.aip.gateway.api.controller;

import com.aip.gateway.api.model.file.UploadFileResponse;
import com.aip.gateway.api.model.request.RequestFile;
import com.aip.gateway.api.model.request.RequestFileAllSet;
import com.aip.gateway.api.model.request.RequestFileDel;
import com.aip.gateway.api.model.request.RequestFileSet;
import com.aip.gateway.api.model.response.ApiResponseModel;
import com.aip.gateway.api.repository.AppRepository;
import com.aip.gateway.api.repository.GlobalConstants;
import com.aip.gateway.api.service.FileStorageService;
import com.aip.gateway.api.service.IApiFileService;
import io.swagger.annotations.ApiOperation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import java.io.IOException;

@Slf4j
@Tag(name = "ApiFile", description = "FILE AIP API")
@RestController
@RequiredArgsConstructor
@CrossOrigin
@Validated
@RequestMapping("/v1/aip-api/file")
public class ApiFileController extends  BaseController {

    private final AppRepository appRepo;
    private final IApiFileService service;
    private final FileStorageService fileStorageService;

    @Operation(summary = "File Info", description = "AIP File Information Query.")
    @ApiResponse(responseCode = "200", description = "AIP File Information query Success.")
    @ApiOperation(value = "File Info", response = ApiResponseModel.class)
    @PostMapping(value = "info", produces = {"application/json; charset=utf8"})
    public ResponseEntity<ApiResponseModel> getInfo(
            @Parameter(name = "req", description = "File 정보 요청 데이터", required = true)
            @RequestBody @Valid final RequestFile req, HttpServletRequest request)
    {
        try {
            GlobalConstants.setAuthorization(request, GlobalConstants.API_FILE_INFO, req.getApiKey(), req);
            int authError = this.appRepo.checkApiKeyValidation(req.getApiKey(), getRemoteIP(request));
            if (authError != 0) {
                return responseApiKeyValidationError(request, authError);
            }
            return responseSuccess(request, this.service.getInfo(req));
        }
        catch (Exception e) {
            log.error("exception: /v1/aip-api/file/info, {}", e.getMessage());
            return responseException(request, e);
        }
    }

    @Operation(summary = "File AIP Label 설정", description = "File AIP Label Set.")
    @ApiResponse(responseCode = "200", description = "File AIP Label set success.")
    @ApiOperation(value = "File AIP Label 설정", response = ApiResponseModel.class, responseContainer = "ArrayList")
    @PostMapping(value = "set-label", produces = {"application/json; charset=utf8"})
    public ResponseEntity<ApiResponseModel> setLabel(
            @Parameter(name = "req", description = "File AIP Label 설정 요청 데이터", required = true)
            @RequestBody @Valid final RequestFileSet req, HttpServletRequest request)
    {
        try {
            GlobalConstants.setAuthorization(request, GlobalConstants.API_FILE_SET_LABEL, req.getApiKey(), req);
            int authError = this.appRepo.checkApiKeyValidation(req.getApiKey(), getRemoteIP(request));
            if (authError != 0) {
                return responseApiKeyValidationError(request, authError);
            }
            return responseSuccess(request, this.service.setLabel(req));
        }
        catch (Exception e) {
            log.error("exception: /v1/aip-api/file/set-label, {}", e.getMessage());
            return responseException(request, e);
        }
    }

    @Operation(summary = "File AIP Label Delete", description = "File AIP Label Delete.")
    @ApiResponse(responseCode = "200", description = "File AIP Label delete success.")
    @ApiOperation(value = "File AIP Label 해제", response = ApiResponseModel.class, responseContainer = "ArrayList")
    @PostMapping(value = "delete-label", produces = {"application/json; charset=utf8"})
    public ResponseEntity<ApiResponseModel> delLabel(
            @Parameter(name = "req", description = "File AIP Label 해제 요청 데이터", required = true)
            @RequestBody @Valid final RequestFileDel req, HttpServletRequest request)
    {
        try {
            GlobalConstants.setAuthorization(request, GlobalConstants.API_FILE_DELETE_LABEL, req.getApiKey(), req);
            int authError = this.appRepo.checkApiKeyValidation(req.getApiKey(), getRemoteIP(request));
            if (authError != 0) {
                return responseApiKeyValidationError(request, authError);
            }
            return responseSuccess(request, this.service.delLabel(req));
        }
        catch (Exception e) {
            log.error("exception: /v1/aip-api/file/delete-label, {}", e.getMessage());
            return responseException(request, e);
        }
    }

    @Operation(summary = "File AIP Protection 설정", description = "File AIP Protection AIP.")
    @ApiResponse(responseCode = "200", description = "File AIP Protection set success.")
    @ApiOperation(value = "File AIP Protection 설정", response = ApiResponseModel.class, responseContainer = "ArrayList")
    @PostMapping(value = "set-protection", produces = {"application/json; charset=utf8"})
    public ResponseEntity<ApiResponseModel> setProtection(
            @Parameter(name = "req", description = "File AIP Protection 설정 요청 데이터", required = true)
            @RequestBody @Valid final RequestFileSet req, HttpServletRequest request)
    {
        try {
            GlobalConstants.setAuthorization(request, GlobalConstants.API_FILE_SET_PROTECTION, req.getApiKey(), req);
            int authError = this.appRepo.checkApiKeyValidation(req.getApiKey(), getRemoteIP(request));
             if (authError != 0) {
                 return responseApiKeyValidationError(request, authError);
             }
             return responseSuccess(request, this.service.setProtection(req));
        }
        catch (Exception e) {
            log.error("exception: /v1/aip-api/file/set-protection, {}", e.getMessage());
            return responseException(request, e);
        }
    }

    @Operation(summary = "File AIP Protection Delete", description = "File AIP Protection Delete.")
    @ApiResponse(responseCode = "200", description = "File AIP Protection delete success.")
    @ApiOperation(value = "File AIP Protection 해제", response = ApiResponseModel.class, responseContainer = "ArrayList")
    @PostMapping(value = "delete-protection", produces = {"application/json; charset=utf8"})
    public ResponseEntity<ApiResponseModel> delProtection(
            @Parameter(name = "req", description = "File AIP Protection 해제 요청 데이터", required = true)
            @RequestBody @Valid final RequestFileDel req, HttpServletRequest request)
    {
        try {
            GlobalConstants.setAuthorization(request, GlobalConstants.API_FILE_DELETE_PROTECTIN, req.getApiKey(), req);
            int authError = this.appRepo.checkApiKeyValidation(req.getApiKey(), getRemoteIP(request));
            if (authError != 0) {
                return responseApiKeyValidationError(request, authError);
            }
            return responseSuccess(request, this.service.delProtection(req));
        }
        catch (Exception e) {
            log.error("exception: /v1/aip-api/file/delete-protection, {}", e.getMessage());
            return responseException(request, e);
        }
    }

    @Operation(summary = "File AIP Label Or Protection 설정", description = "File AIP Label Or Protection AIP.")
    @ApiResponse(responseCode = "200", description = "File AIP Label Or Protection set success.")
    @ApiOperation(value = "File AIP Label Or Protection 설정", response = ApiResponseModel.class, responseContainer = "ArrayList")
    @PostMapping(value = "set-label-protection", produces = {"application/json; charset=utf8"})
    public ResponseEntity<ApiResponseModel> setLabelProtection(
            @Parameter(name = "req", description = "File AIP Label Or Protection 설정 요청 데이터", required = true)
            @RequestBody @Valid final RequestFileAllSet req, HttpServletRequest request)
    {
        try {
            GlobalConstants.setAuthorization(request, GlobalConstants.API_FILE_SET_LABEL_PROTECTION, req.getApiKey(), req);
            int authError = this.appRepo.checkApiKeyValidation(req.getApiKey(), getRemoteIP(request));
            if (authError != 0) {
                return responseApiKeyValidationError(request, authError);
            }
            return responseSuccess(request, this.service.setLabelProtection(req));
        }
        catch (Exception e) {
            log.error("exception: /v1/aip-api/file/set-label-protection, {}", e.getMessage());
            return responseException(request, e);
        }
    }

    @Operation(summary = "File AIP Label Or Protection Delete", description = "File AIP Label Or Protection Delete.")
    @ApiResponse(responseCode = "200", description = "File AIP Label Or Protection delete success.")
    @ApiOperation(value = "File AIP Label Or Protection 해제", response = ApiResponseModel.class, responseContainer = "ArrayList")
    @PostMapping(value = "delete-label-protection", produces = {"application/json; charset=utf8"})
    public ResponseEntity<ApiResponseModel> delLabelProtection(
            @Parameter(name = "req", description = "File AIP Label Or Protection 해제 요청 데이터", required = true)
            @RequestBody @Valid final RequestFileDel req, HttpServletRequest request)
    {
        try {
            GlobalConstants.setAuthorization(request, GlobalConstants.API_FILE_DELETE_LABEL_PROTECTION, req.getApiKey(), req);
            int authError = this.appRepo.checkApiKeyValidation(req.getApiKey(), getRemoteIP(request));
            if (authError != 0) {
                return responseApiKeyValidationError(request, authError);
            }
            return responseSuccess(request, this.service.delLabelProtection(req));
        }
        catch (Exception e) {
            log.error("exception: /v1/aip-api/file/delete-label-protection, {}", e.getMessage());
            return responseException(request, e);
        }
    }

    // https://www.callicoder.com/spring-boot-file-upload-download-rest-api-example/
    @PostMapping(value = "uploadFile", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE})
    public UploadFileResponse uploadFile(
            @Parameter(description = "multipart/form-data 형식의 파일을 input 으로 받습니다. 이때 key 값은 multipartFile 입니다.")
            @RequestParam("file") MultipartFile file,
            @RequestParam("apiKey") String apiKey,
            @RequestParam("password") String password,
            @RequestParam("email") String email)
    {
        log.error("    file: {}", file.getOriginalFilename());
        log.error("    file: {}", file.getName());
        String fileName = fileStorageService.storeFile(file);
        log.error("fileName: {}", fileName);
        log.error("  apiKey: {}", apiKey);
        log.error("password: {}", password);
        log.error("   email: {}", email);

        String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
                .path("/downloadFile/")
                .path(fileName)
                .toUriString();

        return new UploadFileResponse(fileName, fileDownloadUri,
                file.getContentType(), file.getSize());
    }
//    @PostMapping("/uploadMultipleFiles")
//    public List<UploadFileResponse> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) {
//        return Arrays.asList(files)
//                .stream()
//                .map(file -> uploadFile(file))
//                .collect(Collectors.toList());
//    }

    @GetMapping("/downloadFile/{fileName:.+}")
    public ResponseEntity<Resource> downloadFile(@PathVariable String fileName, HttpServletRequest request) {
        // Load file as Resource
        Resource resource = fileStorageService.loadFileAsResource(fileName);

        // Try to determine file's content type
        String contentType = null;
        try {
            contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
        } catch (IOException ex) {
            log.info("Could not determine file type.");
        }

        // Fallback to the default content type if type could not be determined
        if(contentType == null) {
            contentType = "application/octet-stream";
        }

        return ResponseEntity.ok()
                .contentType(MediaType.parseMediaType(contentType))
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
                .body(resource);
    }

}
