package org.springblade.file.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import org.springblade.core.boot.ctrl.BladeController;
import org.springblade.core.log.annotation.ApiLog;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.file.listener.FileEvent;
import org.springblade.file.pojo.dto.CertificateAttachmentDTO;
import org.springblade.file.pojo.dto.FileCertificateBatchRecognitionDTO;
import org.springblade.file.pojo.entity.Attachment;
import org.springblade.file.service.IAttachmentService;
import org.springblade.file.service.IFileService;
import org.springblade.file.service.IOCRConvertService;
import org.springblade.thirdparty.ocr.pojo.dto.CertificateRecognitionDTO;
import org.springblade.thirdparty.ocr.pojo.vo.TransportCertificateVO;
import org.springblade.thirdparty.ocr.service.IOCRService;
import org.springblade.thirdparty.wps.service.IWpsService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
 * @ClassName: fileUploadController
 * @Author: zhaowei
 * @Date: 2024/8/22
 */
@Valid
@NonDS
@RestController
@AllArgsConstructor
@RequestMapping("/file")
@Tag(name = "文件相关管理", description = "文件相关管理")
public class FileController extends BladeController {

    private final IAttachmentService attachmentService;
    private final IFileService fileService;
    private final IWpsService wpsService;
    private final IOCRService ocrService;
    private final IOCRConvertService ocrConvertService;
    private final ApplicationContext applicationContext;

    @ApiLog("附件管理-批量上传")
    @Operation(summary = "OBS批量上传", description = "OBS批量上传，参数名：files")
    @PostMapping("/ossUpload")
    public R ossUpload(MultipartFile[] files, @RequestParam(value = "fileName", required = false) String fileName) {
        return attachmentService.batchOssUpload(files, fileName);
    }

	@Operation(summary = "上传", description = "上传，参数名：file")
    @PostMapping("/upload")
    public R upload(MultipartFile file) {
		MultipartFile[] files = {file};
		R<List<Attachment>> result = attachmentService.batchOssUpload(files, null);
		List<Attachment> data = result.getData();
		if(data != null && !data.isEmpty())return R.data(data.get(0));
        return R.fail("上传失败");
    }

    @Operation(summary = "获取附件，多个附件id用逗号分割", description = "获取附件，多个附件id用逗号分割")
    @GetMapping("/getAttachment")
    public R getAttachment(@RequestParam(value = "id") String id) {
        return R.data(attachmentService.getAttachment(id));
    }

    @Operation(summary = "获取文件url", description = "获取文件url，参数:objectKey")
    @GetMapping("/getFileUrl")
    public R getFileUrl(@RequestParam(value = "objectKey") String objectKey, @RequestParam(value = "attachmentName", required = false) String attachmentName) {
        if (StringUtil.isBlank(attachmentName)) {
            // 附件名为空，查询附件名
            Attachment attachment = attachmentService.getOne(Wrappers.<Attachment>lambdaQuery()
                    .eq(Attachment::getObjectKey, objectKey)
                    .last("limit 1")
            );
            attachmentName = Optional.ofNullable(attachment)
                    .map(Attachment::getAttachmentName)
                    .orElse(null);
            if (attachmentName != null) {
                // 附件名中如果有逗号，则替换为下划线
                attachmentName = attachmentName.replaceAll(",", "_");
            }
        }
        return R.data(fileService.getFileUrl(objectKey, attachmentName, null));
    }

    /**
     *  获取wps文件预览url
     * @param attachmentId     * @param attachmentName
     * @return
     */
    @Operation(summary = "获取wps文件预览url", description = "获取wps文件预览url")
    @GetMapping("/getWpsFilePreviewUrl")
    public R getWpsFilePreviewUrl(@NotNull(message = "附件id不能为空") @RequestParam(value = "attachmentId", required = false) String attachmentId,
                                  @NotBlank(message = "附件名称不能为空") @RequestParam(value = "attachmentName", required = false) String attachmentName) {
        return R.data(wpsService.getFilePreviewUrl(attachmentId, attachmentName));
    }

    /**
     *  获取wps文件编辑url
     * @param attachmentId
     * @param attachmentName
     * @return
     */
    @Operation(summary = "获取wps文件编辑url", description = "获取wps文件编辑url")
    @GetMapping("/getWpsFileEditUrl")
    public R getWpsFileEditUrl(@NotNull(message = "附件id不能为空") @RequestParam(value = "attachmentId", required = false) String attachmentId,
                                  @NotBlank(message = "附件名称不能为空") @RequestParam(value = "attachmentName", required = false) String attachmentName) {
        return R.data(wpsService.getWpsFileEditUrl(attachmentId, attachmentName));
    }

    @Operation(summary = "批量获取文件url", description = "批量获取文件url，参数:objectKey数组")
    @PostMapping("/getFileUrls")
    public R getFileUrls(@RequestBody List<String> objectKeys) {
        return R.data(fileService.getFileUrls(objectKeys, null));
    }

    @ApiLog("OCR识别-识别身份证")
    @Operation(summary = "识别身份证信息支持正反面", description = "参数:url")
    @GetMapping("/recognitionIDCard")
    public R recognitionIDCard(@RequestParam(value = "url", required = false) String url,
                               @RequestParam(value = "objectKey", required = false) String objectKey) {
        String imageUrl = StringUtil.isNotBlank(url) ? url : objectKey;
        if (StringUtil.isBlank(imageUrl)) {
            return R.fail("图片地址不能为空");
        }
        if (!imageUrl.startsWith("http://") && !imageUrl.startsWith("https://")) {
            imageUrl = fileService.getFileUrl(imageUrl, null);
        }
        return R.data(ocrService.recognitionIDCard(List.of(imageUrl)));
    }

    @SentinelResource("ocr:batchCards")
    @ApiLog("OCR识别-识别车辆运输凭证（不知道类型）")
    @Operation(summary = "识别车辆运输凭证，不知道类型", description = "参数:objectKeylist")
    @PostMapping("/recognitionTransportCertificates")
    public R<TransportCertificateVO> recognitionTransportCertificates(
            @RequestBody List<Object> attachments,
            @RequestParam(value = "projectAbbreviation", required = false) String projectAbbreviation,
            @RequestParam(value = "code", required = false) String code) {
        return R.data(ocrConvertService.recognitionTransportCertificate(
                buildCertificateBatchRecognitionDTO(attachments, projectAbbreviation, code)
        ));
    }

    private FileCertificateBatchRecognitionDTO buildCertificateBatchRecognitionDTO(
            List<Object> attachments, String projectAbbreviation, String code) {
        List<String> objectKeys = new ArrayList<>();
        List<String> poundUrls = new ArrayList<>();
        List<String> carFrontUrls = new ArrayList<>();
        List<String> driverLicenseUrls = new ArrayList<>();
        List<String> vehicleLicenseUrls = new ArrayList<>();
        for (Object attachment : Optional.ofNullable(attachments).orElse(List.of())) {
            if (attachment instanceof String objectKey) {
                if (StringUtil.isNotBlank(objectKey)) {
                    objectKeys.add(objectKey);
                }
                continue;
            }
            if (attachment instanceof Map<?, ?> attachmentMap) {
                String objectKey = getAttachmentObjectKey(attachmentMap);
                if (StringUtil.isBlank(objectKey)) {
                    continue;
                }
                objectKeys.add(objectKey);
                addTypedObjectKeys(attachmentMap, poundUrls, carFrontUrls, driverLicenseUrls, vehicleLicenseUrls);
            }
        }
        FileCertificateBatchRecognitionDTO dto = new FileCertificateBatchRecognitionDTO(
                objectKeys, projectAbbreviation, code, null
        );
        dto.setPoundUrls(poundUrls);
        dto.setCarFrontUrls(carFrontUrls);
        dto.setDriverLicenseUrls(driverLicenseUrls);
        dto.setVehicleLicenseUrls(vehicleLicenseUrls);
        return dto;
    }

    private String getAttachmentObjectKey(Map<?, ?> map) {
        String objectKey = getMapString(map, "objectKey");
        if (StringUtil.isNotBlank(objectKey)) {
            return objectKey;
        }
        String url = getMapString(map, "url");
        if (StringUtil.isNotBlank(url)) {
            return url;
        }
        String poundUrl = getMapString(map, "poundUrl");
        if (StringUtil.isNotBlank(poundUrl)) {
            return poundUrl;
        }
        String carFrontUrl = getMapString(map, "carFrontUrl");
        if (StringUtil.isNotBlank(carFrontUrl)) {
            return carFrontUrl;
        }
        String driverLicenseUrl = getMapString(map, "driverLicenseUrl");
        if (StringUtil.isNotBlank(driverLicenseUrl)) {
            return driverLicenseUrl;
        }
        return getMapString(map, "vehicleLicenseUrl");
    }

    private void addTypedObjectKeys(
            Map<?, ?> map,
            List<String> poundUrls,
            List<String> carFrontUrls,
            List<String> driverLicenseUrls,
            List<String> vehicleLicenseUrls) {
        addMapString(map, "poundUrl", poundUrls);
        addMapString(map, "carFrontUrl", carFrontUrls);
        addMapString(map, "driverLicenseUrl", driverLicenseUrls);
        addMapString(map, "vehicleLicenseUrl", vehicleLicenseUrls);
    }

    private void addMapString(Map<?, ?> map, String key, List<String> values) {
        String value = getMapString(map, key);
        if (StringUtil.isNotBlank(value)) {
            values.add(value);
        }
    }

    private String getMapString(Map<?, ?> map, String key) {
        Object value = map.get(key);
        return value == null ? "" : String.valueOf(value);
    }

    @ApiLog("OCR识别-识别车辆运输凭证（知道类型）")
    @Operation(summary = "识别车辆运输凭证，知道类型", description = "参数:objectKeylist")
    @PostMapping("/recognitionTransportCertificatesByType")
    public R<TransportCertificateVO> recognitionTransportCertificatesByType(@RequestBody CertificateAttachmentDTO param, @RequestParam(value = "code", required = false) String code) {
        CertificateRecognitionDTO recognitionParam = new CertificateRecognitionDTO();
        recognitionParam.setPoundUrl(fileService.getFileUrl(param.getPoundObjectKey(), null));
        recognitionParam.setCarFrontUrl(fileService.getFileUrl(param.getCarFrontObjectKey(), null));
        recognitionParam.setDriverLicenseUrl(fileService.getFileUrl(param.getDriverLicenseObjectKey(), null));
        recognitionParam.setVehicleLicenseUrl(fileService.getFileUrl(param.getVehicleLicenseObjectKey(), null));
        recognitionParam.setName(param.getProjectAbbreviation());
        return R.data(ocrService.recognitionTransportCertificate(recognitionParam, code));
    }

    @Operation(hidden = true)
    @PostMapping("/publishEvent")
    public R<Boolean> publishEvent(String code, Long id) {
        ApplicationEvent event = FileEvent.createEvent(code, id);
        if (event == null) {
            return R.fail("事件名称错误");
        }
        applicationContext.publishEvent(event);
        return R.status(true);
    }
}
