package com.jwipc.sys.logic.impl;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.jwipc.exception.DaoException;
import com.jwipc.security.LoginUtil;
import com.jwipc.sys.client.SequenceClient;
import com.jwipc.sys.constant.SysKingdeeImageClient;
import com.jwipc.sys.dto.BusinessAttachmentDTO;
import com.jwipc.sys.dto.FileResposeDTO;
import com.jwipc.sys.dto.KingdeeImageApiResultDTO;
import com.jwipc.sys.dto.KingdeeInvoiceCloudImageDTO;
import com.jwipc.sys.entity.BusinessAttachment;
import com.jwipc.sys.logic.FileLogic;
import com.jwipc.sys.logic.KingdeeImageLogic;
import com.jwipc.sys.service.IBusinessAttachmentService;
import com.jwipc.sys.util.FinancialShareUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 金蝶影像系统-逻辑实现类
 * </p>
 *
 * @author Chen Tianshi
 * @since 2025/10/13 16:47
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class KingdeeImageLogicImpl implements KingdeeImageLogic {

    private final FileLogic fileLogic;
    private final IBusinessAttachmentService businessAttachmentService;
    private final SysKingdeeImageClient sysKingdeeImageClient;
    private final SequenceClient sequenceClient;
    private final FinancialShareUtil financialShareUtil;

    /**
     * 推送影像文件到影像系统
     *
     * @param pushDTO 业务附件明细、单据编码
     */
    @Override
    public KingdeeInvoiceCloudImageDTO pushImage(KingdeeInvoiceCloudImageDTO pushDTO) {
        KingdeeInvoiceCloudImageDTO result = new KingdeeInvoiceCloudImageDTO();
        List<BusinessAttachmentDTO> businessAttachmentList = pushDTO.getBusinessAttachmentList();
        if (CollectionUtils.isEmpty(businessAttachmentList)) {
            return null;
        }
        List<BusinessAttachmentDTO> uploadSuccessList = Lists.newArrayList();
        List<String> errorMessages = Lists.newArrayList();
        // 1.上传文件
        for (BusinessAttachmentDTO businessAttachmentDTO : businessAttachmentList) {
//            try {
            if (StringUtils.isEmpty(businessAttachmentDTO.getImageFileId())) {
                // 1.1获取影像编码
                String fileId = uploadFiles(businessAttachmentDTO.getFileId());
                // 1.2更新影像编码
                if (!StringUtils.equals(businessAttachmentDTO.getType(), "invoice")) {
                    // 只需要更新签署附件的，排除关联发票
                    if (businessAttachmentDTO.getId() != null) {
                        businessAttachmentService.update(new LambdaUpdateWrapper<BusinessAttachment>()
                                .set(BusinessAttachment::getImageFileId, fileId)
                                .set(BusinessAttachment::getUpdateUser, LoginUtil.getUserId())
                                .set(BusinessAttachment::getUpdateTime, LocalDateTime.now())
                                .eq(BusinessAttachment::getId, businessAttachmentDTO.getId()));
                    }
                }
                businessAttachmentDTO.setImageFileId(fileId);
            }
            uploadSuccessList.add(businessAttachmentDTO);
//            } catch (DaoException e) {
//                errorMessages.add("推送文件（" + businessAttachmentDTO.getFileName() + "）时发生错误:" + e.getMessage());
//            }
        }

        // 2.绑定关系
        String imageCode;
        if (StringUtils.isNotEmpty(pushDTO.getImageCode())) {
            imageCode = pushDTO.getImageCode();
        } else {
            imageCode = sequenceClient.createSequenceNo("image_code");
        }
        bindingImageRelation(imageCode, uploadSuccessList);

        // 3.更新影像编码、地址
        // 3.1获取更新对象ID
        List<Long> updateIds = Lists.newArrayList();
        uploadSuccessList.forEach(item -> updateIds.add(item.getId()));
        // 3.2获取影像地址
        String imagePath = getImageViewPath(imageCode);
        // 3.3更新
        businessAttachmentService.update(new LambdaUpdateWrapper<BusinessAttachment>()
                .set(BusinessAttachment::getImageCode, imageCode)
                .set(BusinessAttachment::getImagePath, imagePath)
                .set(BusinessAttachment::getUpdateUser, LoginUtil.getUserId())
                .set(BusinessAttachment::getUpdateTime, LocalDateTime.now())
                .in(BusinessAttachment::getId, updateIds));

        // 4 提醒失败文件
        if (!CollectionUtils.isEmpty(errorMessages)) {
            StringBuilder errorStr = new StringBuilder();
            for (String error : errorMessages) {
                if (!StringUtils.isNotEmpty(error)) {
                    errorStr.append("<br>");
                }
                errorStr.append(error);
            }
            throw new DaoException(errorStr.toString());
        }
        result.setBusinessAttachmentList(uploadSuccessList);
        result.setImagePath(imagePath);
        result.setImageCode(imageCode);
        return result;
    }

    /**
     * 删除影像（整单删除）
     *
     * @param deleteDTO 业务附件明细、单据编码、删除原因
     */
    @Override
    public void deleteAllImage(KingdeeInvoiceCloudImageDTO deleteDTO) {
        List<BusinessAttachmentDTO> businessAttachmentList = deleteDTO.getBusinessAttachmentList();
        String imageCode = deleteDTO.getImageCode();
        String deleteReason = "整单删除";
        // 1.删除影像
        JSONObject reqBody = new JSONObject();
        reqBody.put("scanBillNo", imageCode);
        reqBody.put("deleteReason", deleteReason);

        KingdeeImageApiResultDTO imageApiResult = sysKingdeeImageClient.deleteBillImage(reqBody, financialShareUtil.getImageAccessToken());
        if (!StringUtils.equals("0000", imageApiResult.getErrcode())) {
            handleErrorMessage(imageApiResult.getDescription(), "删除影像");
        }

        // 2.清空业务附件的影像编码、影像地址
        if (!CollectionUtils.isEmpty(businessAttachmentList)) {
            List<Long> updateIds = Lists.newArrayList();
            businessAttachmentList.forEach(item -> updateIds.add(item.getId()));
            businessAttachmentService.update(new LambdaUpdateWrapper<BusinessAttachment>()
                    .set(BusinessAttachment::getImageFileId, null)
                    .set(BusinessAttachment::getImageCode, null)
                    .set(BusinessAttachment::getImagePath, null)
                    .set(BusinessAttachment::getUpdateUser, LoginUtil.getUserId())
                    .set(BusinessAttachment::getUpdateTime, LocalDateTime.now())
                    .in(BusinessAttachment::getId, updateIds));
        }
    }

    /**
     * 删除影像
     *
     * @param deleteDTO 单据编码、影像编码
     */
    @Override
    public void deleteImage(KingdeeInvoiceCloudImageDTO deleteDTO) {
        JSONObject reqBody = new JSONObject();
        reqBody.put("fscanBillNo", deleteDTO.getImageCode());
        JSONArray fileIds = new JSONArray();
        List<BusinessAttachmentDTO> businessAttachmentList = deleteDTO.getBusinessAttachmentList();
        for (BusinessAttachmentDTO deleteItem : businessAttachmentList) {
            fileIds.add(deleteItem.getImageFileId());
        }
        reqBody.put("fileIds", fileIds);

        KingdeeImageApiResultDTO imageApiResult = sysKingdeeImageClient.deleteImage(reqBody, financialShareUtil.getImageAccessToken());
        if (!StringUtils.equals("0000", imageApiResult.getErrcode())) {
            handleErrorMessage(imageApiResult.getDescription(), "删除影像");
        }

        // 清空业务附件的影像编码、影像地址
        if (!CollectionUtils.isEmpty(businessAttachmentList)) {
            List<Long> updateIds = Lists.newArrayList();
            businessAttachmentList.forEach(item -> updateIds.add(item.getId()));
            businessAttachmentService.update(new LambdaUpdateWrapper<BusinessAttachment>()
                    .set(BusinessAttachment::getImageFileId, null)
                    .set(BusinessAttachment::getImageCode, null)
                    .set(BusinessAttachment::getImagePath, null)
                    .set(BusinessAttachment::getUpdateUser, LoginUtil.getUserId())
                    .set(BusinessAttachment::getUpdateTime, LocalDateTime.now())
                    .in(BusinessAttachment::getId, updateIds));
        }
    }

    /**
     * 获取影像查看页面地址
     *
     * @param imageCode 影像编码
     * @return 影像查看页面地址
     */
    @Override
    public String getImageViewPath(String imageCode) {
        JSONObject reqBody = new JSONObject();
        reqBody.put("scanBillNo", imageCode);

        KingdeeImageApiResultDTO imageApiResult = sysKingdeeImageClient.getImageViewPath(reqBody, financialShareUtil.getImageAccessToken());
        JSONObject data = handleApiResult(imageApiResult, "获取影像查看页面地址");
        return data.getString("url");
    }

    /**
     * 上传文件到影像
     *
     * @param fileId 文件ID
     * @return 影像编码
     */
    private String uploadFiles(Long fileId) {
        FileResposeDTO fileResposeDTO = fileLogic.getForDownload(fileId);
        String filePath = fileResposeDTO.getFilePath();
        if (!FileUtil.exist(filePath)) {
            String errorMessage = String.format(
                    "文件%s不存在",
                    fileResposeDTO.getFileName()
            );
            log.error(errorMessage);
            throw new DaoException("推送影像时发生错误：" + errorMessage);
        }
        byte[] fileBytes;
        try {
            fileBytes = Files.readAllBytes(Paths.get(fileResposeDTO.getFilePath()));
        } catch (IOException e) {
            throw new DaoException("文件【" + fileResposeDTO.getFileName() + "】不存在");
        }

        KingdeeImageApiResultDTO imageApiResult = sysKingdeeImageClient.uploadFile(fileBytes, fileResposeDTO.getFileName(), "2", financialShareUtil.getImageAccessToken());
        JSONObject data = handleApiResult(imageApiResult, "推送影像");
        return data.getString("fileId");
    }

    /**
     * 通过单据编码获取已绑定的影像对象
     *
     * @param billNo 单据编码
     * @return 已绑定的影像对象
     */
    private JSONArray getBoundImageIdList(String billNo) {
        JSONObject reqBody = new JSONObject();
        reqBody.put("fscanBillNo", billNo);

        KingdeeImageApiResultDTO imageApiResult = sysKingdeeImageClient.getBoundImageIdList(reqBody, financialShareUtil.getImageAccessToken());
        if (StringUtils.equals("10102", imageApiResult.getErrcode())) {
            return null;
        }
        JSONObject data = handleApiResult(imageApiResult, "获取单据影像明细");
        return data.getJSONArray("scanOutsideFileVoList");
    }

    /**
     * 绑定单据影像关系
     *
     * @param billNo     单据编码
     * @param targetList 必须包含影像编码、业务附件类型
     */
    private void bindingImageRelation(String billNo, List<BusinessAttachmentDTO> targetList) {
        // 1.获取已存在的关系
        JSONArray existRelationList = getBoundImageIdList(billNo);

        boolean hasCover = false;
        if (existRelationList != null) {
            for (int i = 0; i < existRelationList.size(); i++) {
                JSONObject item = existRelationList.getJSONObject(i); // 获取数组中的每个对象
                if (item.getIntValue("fscanType") == 0) {
                    hasCover = true;
                }
            }
        }

        // 2.绑定关系
        JSONObject reqBody = new JSONObject();
        reqBody.put("fscanBillNo", billNo);

        JSONArray scanOutsideFileVoList = new JSONArray();
        for (int i = 0; i < targetList.size(); i++) {
            String fileId = targetList.get(i).getImageFileId();
            JSONObject scanOutsideFileVo = new JSONObject();
            if (StringUtils.equals(targetList.get(i).getType(), "invoice")) {
                // 发票
                scanOutsideFileVo.put("coverFlag", 0);
            } else {
                // 附件
                scanOutsideFileVo.put("coverFlag", 2);
            }
            if (!hasCover && i == 0) {
                // 封面
                scanOutsideFileVo.put("coverFlag", 1);
            }
            scanOutsideFileVo.put("fileId", fileId);
            scanOutsideFileVoList.add(scanOutsideFileVo);
        }
        reqBody.put("scanOutsideFileVoList", scanOutsideFileVoList);

        KingdeeImageApiResultDTO imageApiResult = sysKingdeeImageClient.bindingImageRelation(reqBody, financialShareUtil.getImageAccessToken());
        if (!StringUtils.equals("0000", imageApiResult.getErrcode())) {
            handleErrorMessage(imageApiResult.getDescription(), "绑定影像关系");
        }
    }

    /**
     * 处理请求结果
     *
     * @param apiResultDTO      请求结果
     * @param actionDescription 动作描述
     * @return 成功数据
     */
    private JSONObject handleApiResult(KingdeeImageApiResultDTO apiResultDTO, String actionDescription) {
        if (StringUtils.equals("0000", apiResultDTO.getErrcode())) {
            return apiResultDTO.getData();
        } else {
            handleErrorMessage(apiResultDTO.getDescription(), actionDescription);
            return null;
        }
    }

    private void handleErrorMessage(String error, String actionDescription) {
        String errorMessage = String.format(
                "%s时发生错误，请联系管理员",
                actionDescription
        );
        String logMessage = String.format(
                "%s接口报错：%s",
                actionDescription,
                error
        );
        log.error(logMessage);
        throw new DaoException(logMessage);
    }
}
