package com.njcn.gather.aireport.reportmodel.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.constant.OperateType;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.exception.BusinessException;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.gather.aireport.common.storage.AiReportMinioStorageService;
import com.njcn.gather.aireport.reportmodel.component.ReportModelFileStorageService;
import com.njcn.gather.aireport.reportmodel.pojo.param.ReportModelParam;
import com.njcn.gather.aireport.reportmodel.pojo.po.ReportModelPO;
import com.njcn.gather.aireport.reportmodel.pojo.vo.ReportModelVO;
import com.njcn.gather.aireport.reportmodel.service.ReportModelService;
import com.njcn.gather.comservice.filepreview.FilePreviewService;
import com.njcn.web.controller.BaseController;
import com.njcn.web.utils.HttpResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.InputStreamResource;
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.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;

/**
 * Report model management endpoints.
 */
@Api(tags = "报告模板管理")
@RestController
@RequestMapping("/api/report-model")
@RequiredArgsConstructor
public class ReportModelController extends BaseController {

    private final ReportModelService reportModelService;
    private final ReportModelFileStorageService reportModelFileStorageService;
    private final FilePreviewService filePreviewService;

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @ApiOperation("查询报告模板列表")
    @PostMapping("/list")
    public HttpResult<Page<ReportModelVO>> list(@RequestBody(required = false) ReportModelParam.QueryParam param) {
        String methodDescribe = getMethodDescribe("list");
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS,
                reportModelService.listReportModels(param), methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.ADD)
    @ApiOperation("新增报告模板")
    @PostMapping(value = "/add", consumes = {"multipart/form-data"})
    public HttpResult<Boolean> add(@RequestPart("request") @Validated ReportModelParam.AddParam param,
                                   @RequestPart("templateFile") MultipartFile templateFile) {
        String methodDescribe = getMethodDescribe("add");
        boolean result = reportModelService.addReportModel(param, templateFile);
        return HttpResultUtil.assembleCommonResponseResult(result ? CommonResponseEnum.SUCCESS : CommonResponseEnum.FAIL,
                result, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.UPDATE)
    @ApiOperation("编辑报告模板")
    @PostMapping(value = "/update", consumes = {"multipart/form-data"})
    public HttpResult<Boolean> update(@RequestPart("request") @Validated ReportModelParam.UpdateParam param,
                                      @RequestPart(value = "templateFile", required = false) MultipartFile templateFile) {
        String methodDescribe = getMethodDescribe("update");
        boolean result = reportModelService.updateReportModel(param, templateFile);
        return HttpResultUtil.assembleCommonResponseResult(result ? CommonResponseEnum.SUCCESS : CommonResponseEnum.FAIL,
                result, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.DELETE)
    @ApiOperation("删除报告模板")
    @PostMapping("/delete")
    public HttpResult<Boolean> delete(@RequestBody List<String> ids) {
        String methodDescribe = getMethodDescribe("delete");
        boolean result = reportModelService.deleteReportModels(ids);
        return HttpResultUtil.assembleCommonResponseResult(result ? CommonResponseEnum.SUCCESS : CommonResponseEnum.FAIL,
                result, methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @ApiOperation("查询报告模板详情")
    @ApiImplicitParam(name = "id", value = "模板ID", required = true)
    @GetMapping("/{id}")
    public HttpResult<ReportModelVO> detail(@PathVariable("id") String id) {
        String methodDescribe = getMethodDescribe("detail");
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS,
                reportModelService.getReportModel(id), methodDescribe);
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @ApiOperation("下载报告模板文件")
    @ApiImplicitParam(name = "id", value = "模板ID", required = true)
    @GetMapping("/{id}/download")
    public ResponseEntity<InputStreamResource> download(@PathVariable("id") String id) {
        ReportModelPO model = reportModelService.requireNormal(id);
        try {
            String fileName = resolveFileName(model);
            String encodedFileName = encodeFileName(fileName);
            AiReportMinioStorageService.StoredObject storedObject = reportModelFileStorageService.getObject(model.getPath());
            return ResponseEntity.ok()
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename*=UTF-8''" + encodedFileName)
                    .body(new InputStreamResource(storedObject.getInputStream()));
        } catch (Exception exception) {
            throw new BusinessException(CommonResponseEnum.FAIL, "读取模板文件失败");
        }
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON)
    @ApiOperation("预览报告模板文件")
    @ApiImplicitParam(name = "id", value = "模板ID", required = true)
    @GetMapping("/{id}/preview")
    public ResponseEntity<byte[]> preview(@PathVariable("id") String id) {
        ReportModelPO model = reportModelService.requireNormal(id);
        String fileName = resolveFileName(model);
        Path tempFile = reportModelFileStorageService.downloadToTempFile(model.getPath(), fileName);
        try {
            FilePreviewService.PreviewContent previewContent = filePreviewService.preview(tempFile, fileName);
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION,
                            "inline; filename*=UTF-8''" + encodeFileName(fileName))
                    .header(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate")
                    .contentType(MediaType.parseMediaType(previewContent.getContentType()))
                    .body(previewContent.getContent());
        } finally {
            reportModelFileStorageService.deleteTempFileQuietly(tempFile);
        }
    }

    @OperateInfo(info = LogEnum.BUSINESS_COMMON, operateType = OperateType.UPDATE)
    @ApiOperation("提交报告模板审核")
    @PostMapping("/submit-audit")
    public HttpResult<Boolean> submitAudit(@RequestBody @Validated ReportModelParam.SubmitAuditParam param) {
        String methodDescribe = getMethodDescribe("submitAudit");
        boolean result = reportModelService.submitAudit(param);
        return HttpResultUtil.assembleCommonResponseResult(result ? CommonResponseEnum.SUCCESS : CommonResponseEnum.FAIL,
                result, methodDescribe);
    }

    private String encodeFileName(String fileName) {
        try {
            return URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()).replace("+", "%20");
        } catch (Exception exception) {
            throw new BusinessException(CommonResponseEnum.FAIL, "编码模板文件名失败");
        }
    }

    private String resolveFileName(ReportModelPO model) {
        String fileName = model.getFileName();
        if (fileName == null || fileName.trim().isEmpty()) {
            return reportModelFileStorageService.resolveDownloadFileName(model.getPath());
        }
        return fileName;
    }
}
