package com.jwipc.sys.logic.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jwipc.exception.DaoException;
import com.jwipc.prop.SysProp;
import com.jwipc.security.LoginUtil;
import com.jwipc.sys.client.CompanyClient;
import com.jwipc.sys.client.dto.CompanyDTO;
import com.jwipc.sys.constant.SysKingdeeInvoiceCloudClient;
import com.jwipc.sys.dto.*;
import com.jwipc.sys.entity.TaxInfo;
import com.jwipc.sys.logic.FileLogic;
import com.jwipc.sys.logic.KingdeeInvoiceCloudLogic;
import com.jwipc.sys.service.ITaxService;
import com.jwipc.sys.util.FinancialShareUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.jwipc.sys.constant.ModuleConst.MODULE_ROOT;

/**
 * <p>
 *  金蝶发票云助手-逻辑实现类
 * </p>
 *
 * @author Chen Tianshi
 * @since 2025/9/24 14:51
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class KingdeeInvoiceCloudLogicImpl implements KingdeeInvoiceCloudLogic {

    private final SysProp sysProp;
    private final FileLogic fileLogic;
    private final ITaxService taxService;
    private final CompanyClient companyClient;
    private final SysKingdeeInvoiceCloudClient sysKingdeeInvoiceCloudClient;
    private final FinancialShareUtil financialShareUtil;

    private final static String RESOURCE = "SRM";

    /**
     * 获取发票云助手的eventCode、token
     * @param eventCodeDTO 见金蝶文档（<a href="https://open-ultimate.piaozone.com/doc-3655357">发票云API文档</a>）
     * @return eventCode、token
     */
    @Override
    public KingdeeInvoiceCloudAssistantResultDTO getAssistantInfo(KingdeeInvoiceCloudAssistantEventCodeDTO eventCodeDTO) {
        KingdeeInvoiceCloudAssistantResultDTO resultDTO = new KingdeeInvoiceCloudAssistantResultDTO();
        // 1.获取发票云token
        String accessToken = financialShareUtil.getShareAccessToken();
        resultDTO.setAccessToken(accessToken);
        // 2.获取发票云eventCode

        JSONObject reqBody = new JSONObject();
        reqBody.put("messageType", "getEventCode");
        reqBody.put("messageId", "1");
        eventCodeDTO.setUserId(LoginUtil.getAccount());
        reqBody.put("data", eventCodeDTO);

        KingdeeInvoiceCloudApiResultDTO invoiceCloudResult = sysKingdeeInvoiceCloudClient.getEventCode(accessToken, reqBody);
        JSONObject data = handleApiResult(invoiceCloudResult, "获取发票云eventCode");
        resultDTO.setEventCode(data.getString("eventCode"));
        return resultDTO;
    }

    /**
     * 上传发票，并且推到发票云返回机构化数据
     * @param file 文件流
     * @return 发票结构化数据
     */
    @Override
    public KingdeeInvoiceCloudRecognitionCheckResultDTO recognitionCheck(MultipartFile file,String billId, String orgNumber) {
        KingdeeInvoiceCloudRecognitionCheckResultDTO result = new KingdeeInvoiceCloudRecognitionCheckResultDTO();
        byte[] fileBytes;
        try {
            fileBytes = file.getBytes();
        } catch (IOException e) {
            log.error("获取文件流失败：" + e.getMessage());
            throw new DaoException("系统内部错误，请联系管理员");
        }
        FileResposeDTO fileResposeDTO = fileLogic.uploadFile(file);
        if (fileResposeDTO == null) {
            return null;
        }
        result.setFileId(fileResposeDTO.getId());
        result.setFileName(fileResposeDTO.getFileName());

        JSONObject reqBody = new JSONObject();
        reqBody.put("messageType", "recognitionCheck");
        reqBody.put("messageId", "1");
        JSONObject data = new JSONObject();
        String fileDownUrl = sysProp.getHostUrl() + MODULE_ROOT + "/file/rest/download/" + fileResposeDTO.getId().toString();
        String base64 = Base64.getEncoder().encodeToString(fileBytes);
        data.put("base64", base64);
        data.put("fileDownUrl", fileDownUrl);
        String fileType;
        if (StringUtils.equals(fileResposeDTO.getFileType(), "pdf")) {
            fileType = "1";
        } else if (StringUtils.equalsAny(fileResposeDTO.getFileType(), "png", "jpg")) {
            fileType = "2";
        } else if (StringUtils.equals(fileResposeDTO.getFileType(), "ofd")) {
            fileType = "4";
        } else if (StringUtils.equals(fileResposeDTO.getFileType(), "xml")) {
            fileType = "9";
        } else {
            throw new DaoException("仅支持发票格式为pdf、png、jpg、ofd、xml的文件");
        }
        data.put("fileType", fileType);
        data.put("verifyFlag", "1");
        data.put("billType", "invoice_pool_enter"); // TODO billType、billId为合规性校验必填，详细传参需与金蝶人员确认。
        data.put("billId", billId);
        data.put("orgNumber", orgNumber);
        if (StrUtil.isNotEmpty(orgNumber)){
            CompanyDTO companyDTO = companyClient.getByCode(orgNumber);
            if (ObjectUtil.isNotNull(companyDTO)){
                if (StringUtils.isNotEmpty(companyDTO.getTaxNo())){
                    JSONObject companyInfo = new JSONObject();
                    companyInfo.put("taxNo", companyDTO.getTaxNo());
                    companyInfo.put("name", companyDTO.getCompanyName());
                    data.put("companyInfo", companyInfo);
                }
            }
        }
        data.put("resource", RESOURCE);
        reqBody.put("data", data);

        KingdeeInvoiceCloudApiArrayResultDTO invoiceCloudResult = sysKingdeeInvoiceCloudClient.recognitionCheck(financialShareUtil.getShareAccessToken(), reqBody);
        if (invoiceCloudResult.getStatus()) {
            List<JSONObject> invoiceDataList = invoiceCloudResult.getData();
            String validateMessageHtml = "";
            if (!CollectionUtils.isEmpty(invoiceDataList)) {
                JSONObject invoiceData = invoiceDataList.get(0);
                result.setInvoiceDate(invoiceData.getString("invoiceDate"));
                if (StringUtils.equals("1", invoiceData.getString("isElectricInvoice"))) {
                    result.setInvoiceCode(invoiceData.getString("invoiceCode"));
                    result.setElectronInvoiceNumber(invoiceData.getString("invoiceNo"));
                    List<JSONObject> items = invoiceData.getList("items", JSONObject.class);
                    if (!CollectionUtils.isEmpty(items)) {
                        BigDecimal taxRate = items.get(0).getBigDecimal("taxRate");
                        TaxInfo taxInfo = taxService.getOne(new LambdaQueryWrapper<TaxInfo>().eq(TaxInfo::getTaxValue, taxRate));
                        result.setTaxRate(taxInfo.getTaxCode());
                    }
                } else {
                    result.setInvoiceCode(invoiceData.getString("invoiceCode"));
                    result.setInvoiceNumber(invoiceData.getString("invoiceNo"));
                }
                result.setTaxAmount(invoiceData.getBigDecimal("totalAmount"));
                result.setBuyerName(invoiceData.getString("buyerName"));
                result.setSalerName(invoiceData.getString("salerName"));
                if (invoiceData.getInteger("deductionFlag")!=null){
                    result.setDeductionCodeType(invoiceData.getInteger("deductionFlag")==0?2:1);
                }
                result.setNoTaxAmount(invoiceData.getBigDecimal("invoiceAmount"));
                result.setDiffTaxMoney(invoiceData.getBigDecimal("totalTaxAmount"));
                // 合规性校验结果
                JSONArray verifyResult = invoiceData.getJSONArray("verifyResult");
                if (!verifyResult.isEmpty()) {
                    result.setValidateMessage(invoiceData.getString("validateMessage"));
                }
                validateMessageHtml = invoiceData.getString("validateMessage_html");
                //默认返回0
                result.setType(invoiceData.getInteger("type")==null?0:invoiceData.getInteger("type"));
                result.setSerialNo(invoiceData.getString("serialNo"));
                result.setSubject(invoiceData.getInteger("subject"));
                String remark = invoiceData.getString("remark");
                JSONArray items = invoiceData.getJSONArray("items");
                if (items != null){
                    for (int i = 0; i < items.size(); i++) {
                        JSONObject item = items.getJSONObject(i);
                        BigDecimal taxRate = item.getBigDecimal("taxRate");
                        if (ObjectUtil.isNotNull(taxRate)){
                            TaxInfo taxInfo = taxService.getOne(new LambdaQueryWrapper<TaxInfo>().eq(TaxInfo::getTaxValue, taxRate));
                            item.put("taxRate", taxInfo.getTaxCode());
                        }
                    }
                    result.setItems(items);
                }
                result.setErpRemark(remark);
                if (StrUtil.isNotEmpty(remark)){
                    // 定义正则表达式：匹配“被红冲蓝字数电票号码：”后跟一串数字
                    String regex = "被红冲蓝字数电票号码：(\\d+)";
                    Pattern pattern = Pattern.compile(regex);
                    Matcher matcher = pattern.matcher(remark);
                    if (matcher.find()) {
                        String invoiceNumber = matcher.group(1);
                        result.setBlueInvoiceNo(invoiceNumber);
                        System.out.println("提取的发票号码: " + invoiceNumber);
                    }
                }

            }
            result.setErpJson(JSONUtil.toJsonStr(result).replaceAll("\\\\", ""));
            result.setValidateMessageHtml(validateMessageHtml);
            return result;
        } else {
            String errorMessage = "上传发票时发生错误，请联系管理员";
            String logMessage = String.format(
                    "发票云接口报错：%s",
                    invoiceCloudResult.getMessage()
            );
            log.error(logMessage);
            throw new DaoException(logMessage);
        }
    }

    /**
     * 通过文件url下载发票云文件
     * @param downloadUrl 发票提供的文件下载地址
     * @param fileName 文件名
     * @return 文件信息
     */
    @Override
    public FileResposeDTO downloadAndUploadFile(String downloadUrl, String fileName) {
        // 1. 从金蝶下载文件
        byte[] fileData;
        try {
            fileData = sysKingdeeInvoiceCloudClient.attachmentDownload(downloadUrl, financialShareUtil.getShareAccessToken());
        } catch (Exception e) {
            String errorMessage = "获取发票云文件时发生错误，请联系管理员";
            String logMessage = String.format("获取发票云文件时发生错误，错误信息：%s",e.getMessage());
            log.error(logMessage);
            throw new DaoException(errorMessage);
        }

        // 2. 转换为MultipartFile
        MultipartFile multipartFile = createMultipartFile(
                fileData,
                fileName
        );

        // 3. 调用本地上传服务
        return fileLogic.uploadFile(multipartFile);
    }

    @Override
    public void deleteInvoice(String serialNos) {
        JSONObject reqBody = new JSONObject();
        reqBody.put("messageType", "deleteInvoice");
        reqBody.put("messageId", IdUtil.getSnowflakeNextIdStr());
        JSONObject data = new JSONObject();
        data.put("serialNos", Arrays.asList(serialNos.split(",")));
        reqBody.put("data", data);

        KingdeeInvoiceCloudApiResultDTO invoiceCloudResult = sysKingdeeInvoiceCloudClient.deleteInvoice(financialShareUtil.getShareAccessToken(), reqBody);
        if (!invoiceCloudResult.getStatus()) {
            String logMessage = String.format(
                    "发票云接口报错：%s",
                    invoiceCloudResult.getMessage()
            );
            log.error(logMessage);
            throw new DaoException(logMessage);
        }
    }

    @Override
    public void billSign(String billId,String signType, String serialNos) {
        JSONObject reqBody = new JSONObject();
        reqBody.put("messageType", "billSign");
        reqBody.put("messageId", IdUtil.getSnowflakeNextIdStr());
        JSONObject data = new JSONObject();
        data.put("signType", signType);
//        data.put("billId", billId);
        data.put("bussinSysCode", "srm");
        List<JSONObject> serialNosList = new ArrayList<>();
        List<String> list =  Arrays.asList(serialNos.split(","));
        for (String serialNo : list){
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("serialNo", serialNo);
            serialNosList.add(jsonObject);
        }
        data.put("invoiceData", serialNosList);

        reqBody.put("data", data);

        KingdeeInvoiceCloudApiResultDTO invoiceCloudResult = sysKingdeeInvoiceCloudClient.billSign(financialShareUtil.getShareAccessToken(), reqBody);
        if (!invoiceCloudResult.getStatus()) {
            String logMessage = String.format(
                    "发票云接口报错：%s",
                    invoiceCloudResult.getMessage()
            );
            log.error(logMessage);
            throw new DaoException(logMessage);
        }
    }

    /**
     * 创建MultipartFile对象
     */
    private MultipartFile createMultipartFile(byte[] fileData, String fileName) {
        return new MultipartFile() {
            @Override
            public String getName() { return "file"; }

            @Override
            public String getOriginalFilename() { return fileName; }

            @Override
            public String getContentType() { return null; }

            @Override
            public boolean isEmpty() { return fileData == null || fileData.length == 0; }

            @Override
            public long getSize() { return fileData.length; }

            @Override
            public byte[] getBytes() { return fileData; }

            @Override
            public InputStream getInputStream() {
                return new ByteArrayInputStream(fileData);
            }

            @Override
            public void transferTo(File dest) throws IOException {
                Files.write(dest.toPath(), fileData);
            }
        };
    }

    /**
     * 处理请求结果
     * @param apiResultDTO 请求结果
     * @param actionDescription 动作描述
     * @return 成功数据
     */
    private JSONObject handleApiResult(KingdeeInvoiceCloudApiResultDTO apiResultDTO, String actionDescription) {
        if (apiResultDTO.getStatus()) {
            return apiResultDTO.getData();
        } else {
            String errorMessage = String.format(
                    "%s时发生错误，请联系管理员",
                    actionDescription
            );
            String logMessage = String.format(
                    "%s时发生错误，错误信息：%s",
                    actionDescription,
                    apiResultDTO.getMessage()
            );
            log.error(logMessage);
            throw new DaoException(errorMessage);
        }
    }
}
