package com.malk.guyuan.service.tencent.impl;

import com.alibaba.fastjson.JSON;
import com.malk.guyuan.server.tencent.TXYConf;
import com.malk.guyuan.service.tencent.TXYInvoice;
import com.malk.server.common.McException;
import com.malk.utils.UtilMap;
import com.malk.utils.UtilNumber;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.ocr.v20181119.OcrClient;
import com.tencentcloudapi.ocr.v20181119.models.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

@Slf4j
@Service
public class TXYImplInvoice implements TXYInvoice {

    @Autowired
    private TXYConf txyConf;

    // 创建请求描述
    private ClientProfile doRequest(String endPoint) {

        HttpProfile httpProfile = new HttpProfile();
        httpProfile.setEndpoint(endPoint);
        ClientProfile clientProfile = new ClientProfile();
        clientProfile.setHttpProfile(httpProfile);
        return clientProfile;
    }

    /**
     * 混贴票据识别
     *
     * @apiNote https://cloud.tencent.com/document/product/866/37835
     */
    @Override
    public Map doMixedInvoiceOCR(String image) throws TencentCloudSDKException {

        Credential cred = new Credential(txyConf.getSecretId(), txyConf.getSecretKey());
        ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
        OcrClient client = new OcrClient(cred, txyConf.getRegion(), clientProfile);

        MixedInvoiceOCRRequest req = new MixedInvoiceOCRRequest();
        if (image.startsWith("http")) {
            req.setImageUrl(image);
        } else {
            req.setImageBase64(image);
        }
        req.setReturnMultiplePage(true); // PDF多页识别, 仅支持返回文件前30页
        //log.debug("请求参数, {}", JSON.toJSONString(req));
        MixedInvoiceOCRResponse resp = client.MixedInvoiceOCR(req);
        String result = MixedInvoiceOCRResponse.toJsonString(resp);
        log.debug("请求响应, {}", result);
        return (Map) JSON.parse(result);
    }

    /**
     * 通用票据识别（高级版）
     *
     * @apiNote https://cloud.tencent.com/document/api/866/90802
     */
    @Override
    public Map doRecognizeGeneralInvoice(String image) throws TencentCloudSDKException {
        Credential cred = new Credential(txyConf.getSecretId(), txyConf.getSecretKey());
        ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
        OcrClient client = new OcrClient(cred, txyConf.getRegion(), clientProfile);

        RecognizeGeneralInvoiceRequest req = new RecognizeGeneralInvoiceRequest();
        if (image.startsWith("http")) {
            req.setImageUrl(image);
        } else {
            req.setImageBase64(image);
        }
        req.setEnableMultiplePage(true); // PDF多页识别, 仅支持返回文件前30页
        req.setEnableCutImage(false); // 返回切割图片base64
        RecognizeGeneralInvoiceResponse resp = client.RecognizeGeneralInvoice(req);
        String result = MixedInvoiceOCRResponse.toJsonString(resp);
        log.debug("请求响应, {}", result);
        return (Map) JSON.parse(result);
    }

    /**
     * 发票验真[新版]
     *
     * @apiNote https://cloud.tencent.com/document/product/866/73674
     */
    @Override
    public Map doVatInvoiceVerifyNew(String invoiceKind, String invoiceCode, String invoiceNo, String invoiceDate, String amount, String checkCode, String excludingTax, String tips) throws TencentCloudSDKException {
        Credential cred = new Credential(txyConf.getSecretId(), txyConf.getSecretKey());
        ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
        OcrClient client = new OcrClient(cred, txyConf.getRegion(), clientProfile);

        // 一些特殊发票校验码只有5位, 兼容
        if (StringUtils.isNotBlank(checkCode) && checkCode.length() > 6) {
            checkCode = checkCode.substring(checkCode.length() - 6);
        }

        VatInvoiceVerifyNewRequest req = new VatInvoiceVerifyNewRequest();
        req.setInvoiceNo(invoiceNo);
        req.setInvoiceDate(invoiceDate);
        req.setInvoiceCode(invoiceCode);
        req.setCheckCode(checkCode);
        // ppExt: 全电票, 新版本识别接口, 返回名称为: 电子发票(普通发票) 不包含全电标识, 发类型为: 全电发票. 注意取值
        if (invoiceKind.contains("全电")) {
            // 全电票, 需要价税合计且无发票代码与校验码
            req.setCheckCode(null);
            req.setInvoiceCode(null);
            req.setAmount(amount);
        } else {
            req.setAmount(null);
            req.setAmount(excludingTax);
        }
        log.debug("发票验真, {}, {}", invoiceKind, JSON.toJSONString(req));
        VatInvoiceVerifyNewResponse resp = client.VatInvoiceVerifyNew(req);
        String result = VatInvoiceVerifyNewResponse.toJsonString(resp);
        Map rsp = (Map) JSON.parse(result);

        // 因全电票取值, 取值价税合计, 单独校验下金额
        Map invoice = (Map) rsp.get("Invoice");
        if (StringUtils.isBlank(tips)) {
            tips = "发票有疑问";
        }
        log.debug("请求响应, {}", result);
        McException.assertAccessException(!UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithTax"), amount), tips + ", 价税合计金额不匹配!");
        // ppExt: 增值税卷票: 票面无税率, 税额. 但接口验证返回或本质上发票是有税率, 税额. 因此取消后置判断
        McException.assertAccessException(!invoiceKind.contains("卷票") && !UtilNumber.equalBigDecimal(UtilMap.getString(invoice, "AmountWithoutTax"), excludingTax), tips + ", 不含税金额不匹配!");
        return rsp;
    }

    /**
     * 名片识别
     *
     * @apiNote https://console.cloud.tencent.com/api/explorer?Product=ocr&Version=2018-11-19&Action=BusinessCardOCR
     */
    @Override
    public Map doBusinessCardOCR(String image) throws TencentCloudSDKException {
        Credential cred = new Credential(txyConf.getSecretId(), txyConf.getSecretKey());
        ClientProfile clientProfile = doRequest("ocr.tencentcloudapi.com");
        OcrClient client = new OcrClient(cred, txyConf.getRegion(), clientProfile);

        BusinessCardOCRRequest req = new BusinessCardOCRRequest();
        if (image.startsWith("http")) {
            req.setImageUrl(image);
        } else {
            req.setImageBase64(image);
        }
        req.setConfig(JSON.toJSONString(UtilMap.map("RetImageType", "PROPROCESS")));
        //log.debug("请求参数, {}", JSON.toJSONString(req));
        BusinessCardOCRResponse resp = client.BusinessCardOCR(req);
        String result = BusinessCardOCRResponse.toJsonString(resp);
        log.debug("请求响应, {}", result);
        return (Map) JSON.parse(result);
    }
}
