package com.smppw.modaq.application.components;

import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.smppw.modaq.common.enums.ReportMonthlyType;
import com.smppw.modaq.common.enums.ReportParseStatus;
import com.smppw.modaq.common.exception.ReportParseException;
import com.smppw.modaq.domain.dto.report.OCRParseData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

public class OCRReportParser {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final Map<String, Object> RESULT_SCHEMA_MAP = MapUtil.newHashMap(8);
    private static final Map<String, Object> MONTHLY_TYPE_SCHEMA_MAP = MapUtil.newHashMap(8);

    static {
        RESULT_SCHEMA_MAP.put("基金名称", "");
        RESULT_SCHEMA_MAP.put("产品代码", "");
        RESULT_SCHEMA_MAP.put("是否有红色印章", "");
        RESULT_SCHEMA_MAP.put("是否有电话", "");

        // 管理人版
        MONTHLY_TYPE_SCHEMA_MAP.put("是否有曲线", "");
        // 协会版
        MONTHLY_TYPE_SCHEMA_MAP.put("基金净资产", "");
        MONTHLY_TYPE_SCHEMA_MAP.put("基金份额总额", "");
    }

    public ReportMonthlyType parseMonthlyType(String filename, String ocrApi, String ocrImgUrl) throws ReportParseException {
        Map<String, Object> paramsMap = MapUtil.newHashMap(4);
        paramsMap.put("image_url", ocrImgUrl);
        paramsMap.put("result_schema", JSONUtil.toJsonStr(MONTHLY_TYPE_SCHEMA_MAP));
        ReportMonthlyType res = ReportMonthlyType.FAILED;
        try {
            JSONObject jsonObject = this.parseOcrResult(ocrApi, paramsMap);
            String hasTrend = this.cleanData(jsonObject.getStr("是否有曲线"));
            String netAsset = this.cleanData(jsonObject.getStr("基金净资产"));
            String totalShare = this.cleanData(jsonObject.getStr("基金份额总额"));
            if (StrUtil.isNotBlank(hasTrend)) {
                res = ReportMonthlyType.MANAGER;
            } else if (StrUtil.isAllNotBlank(netAsset, totalShare)
                    && NumberUtil.isNumber(netAsset) && NumberUtil.isNumber(totalShare)) {
                // 这里可能会存在误判，因为部分管理人月报中也有份额和净值
                res = ReportMonthlyType.AMAC;
            }
            return res;
        } catch (IORuntimeException e) {
            throw new ReportParseException(ReportParseStatus.AI_NOT_FOUND);
        } catch (Exception e) {
            this.logger.warn("报告{} OCR提取月报类型错误：{}", filename, e.getMessage());
            throw new ReportParseException(ReportParseStatus.SYSTEM_ERROR);
        } finally {
            if (logger.isInfoEnabled()) {
                this.logger.info("报告{} OCR提取月报类型参数{}，OCR提取月报类型结果：{}", filename, paramsMap, res);
            }
        }
    }

    public OCRParseData parse(String filename, String ocrApi, String ocrImgUrl) throws ReportParseException {
        Map<String, Object> paramsMap = MapUtil.newHashMap(4);
        paramsMap.put("image_url", ocrImgUrl);
        paramsMap.put("result_schema", JSONUtil.toJsonStr(RESULT_SCHEMA_MAP));
        OCRParseData res = new OCRParseData();
        try {
            JSONObject jsonObject = this.parseOcrResult(ocrApi, paramsMap);
            String fundName = this.cleanData(jsonObject.getStr("基金名称"));
            String fundCode = this.cleanData(jsonObject.getStr("产品代码"));
            String seals = this.cleanData(jsonObject.getStr("是否有红色印章"));
            String phone = this.cleanData(jsonObject.getStr("是否有电话"));
            if (StrUtil.isNotBlank(fundName) && fundName.contains("基金") && !fundName.contains("公司")) {
                res.setFundName(fundName);
            }
            if (StrUtil.isNotBlank(fundCode)) {
                res.setFundCode(ReportParseUtils.matchFundCode(fundCode));
            }
            if (StrUtil.isNotBlank(seals)) {
                res.setWithSeals(true);
            }
            if (StrUtil.isNotBlank(phone)) {
                res.setWithContacts(true);
            }
            return res;
        } catch (IORuntimeException e) {
            throw new ReportParseException(ReportParseStatus.AI_NOT_FOUND);
        } catch (Exception e) {
            this.logger.warn("报告{} OCR识别错误：{}", filename, e.getMessage());
            throw new ReportParseException(ReportParseStatus.SYSTEM_ERROR);
        } finally {
            if (logger.isInfoEnabled()) {
                this.logger.info("报告{} OCR识别参数{}，OCR识别结果：{}", filename, paramsMap, res);
            }
        }
    }

    private JSONObject parseOcrResult(String ocrApi, Map<String, Object> paramsMap) {
        String body = HttpUtil.get(ocrApi, paramsMap);
        JSONObject jsonResult = JSONUtil.parseObj(body);
        String content = StrUtil.split(jsonResult.getStr("content"), "```").get(1);
        String aiParserContent = "{" + StrUtil.subAfter(content, "{", false) + "}";
        return JSONUtil.parseObj(aiParserContent);
    }

    private String cleanData(String text) {
        if (text == null) {
            return null;
        }
        String trim = StrUtil.trim(text);
        if (StrUtil.isBlank(trim)) {
            return null;
        }
        if ("无".equals(trim) || "否".equals(trim)) {
            return null;
        }
        String value = ReportParseUtils.cleaningValue(trim);
        if (value == null) {
            return null;
        }
        // 识别到多个基金
        if (value.contains("、") || value.contains("，")) {
            return value.replaceAll("、，", ",");
        }
        return value;
    }
}
