package net.northking.cctp.element.mobile.utils.hzBank;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import net.northking.cctp.element.core.IExecuteContext;
import net.northking.cctp.element.core.exception.ExecuteException;
import net.northking.cctp.element.mobile.constants.ConfigPath;
import net.northking.cctp.element.mobile.constants.HzBankOcr;
import net.northking.cctp.element.mobile.constants.HzBankOcrCode;
import net.northking.cctp.element.mobile.entity.PointMessage;
import net.northking.cctp.element.mobile.utils.HttpUtils;
import net.northking.cctp.element.mobile.vo.HzBankOcrVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

import java.net.URI;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 杭银OCR工具类
 */
public class HzBankOcrUtils {

    private static final Logger logger = LoggerFactory.getLogger(HzBankOcrUtils.class);

    /**
     * 根据Base64图片流请求杭银OCR获取结果
     *
     * @param imgBase64 Base64图片流
     * @param context 配置文件
     * @return 杭银OCR返回结果
     */
    public static String getTextByHzOcr(String imgBase64, IExecuteContext context) {
        String ocrAddress = context.getProperty(ConfigPath.HZBANK_OCR_GET_ALL_TEXT_KEY);
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            JSONObject body = new JSONObject();
            String senderJournalNo = String.valueOf(System.currentTimeMillis());
            body.put("senderJournalNo", senderJournalNo);
            body.put("transCode", HzBankOcr.TRANSCODE);
            body.put("systemCode", HzBankOcr.SYSYEMCODE);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String date = sdf.format(new Date());
            body.put("senderDate", date.substring(0,10));
            body.put("senderTime", date.substring(11));
            body.put("channelCode", HzBankOcr.CHANNELCODE);
            body.put("modeCode", HzBankOcr.MODECODE);
            body.put("imageType", HzBankOcr.IMAGETYPE);
            body.put("imageFlow", imgBase64);
            HttpEntity<String> ocrEntity = new HttpEntity<>(body.toString(),headers);
            JSONObject jsonObject;
            try {
                logger.info("传参：{}", JSON.toJSONString(ocrEntity));
                jsonObject = HttpUtils.doPost(new URI(ocrAddress), ocrEntity, JSONObject.class);
                logger.info("请求杭银Ocr返回结果" + jsonObject.toJSONString());
                HzBankOcrVo hzBankOcrVo = jsonObject.toJavaObject(HzBankOcrVo.class);
                if (jsonObject != null) {
                    String code = hzBankOcrVo.getCode();
                    if (code.equals(HzBankOcrCode.SUCCESS)) {
                        String data = hzBankOcrVo.getData();
                        logger.info("请求杭银Ocr返回结果全部字符为：{}", data);
                        return data;
                    } else if (code.equals(HzBankOcrCode.REQUESTLIMITED)) {
                        logger.info("渠道连接数量超出限制");
                        try {
                            Thread.sleep(1000);
                            getTextByHzOcr(imgBase64, context);
                        } catch (InterruptedException interruptedException) {
                            throw new ExecuteException("请求杭银Ocr停止");
                        }
                    }
                }
            } catch (URISyntaxException e) {
                logger.error("ocr地址有误！===>{}",ocrAddress);
            } catch (Exception e) {
                logger.error("请求ocr接口失败，接口地址：{}",ocrAddress,e);
            }
            return null;
        } catch (Exception e) {
            logger.error("请求杭银ocr接口失败，接口地址：{}",ocrAddress,e);
            throw new ExecuteException("请求杭银ocr接口失败，请查看杭银ocr服务是否开启！");
        }
    }

    /**
     * 根据杭银ocr返回结果获取所有字符
     *
     * @param data 杭银ocr返回结果
     * @return 识别文字
     */
    public static String getAllTextByData(String data) {
        String result = "";
        try {
            JSONObject dataJson = JSONObject.parseObject(data);
            JSONArray allStrArr = JSONArray.parseArray(dataJson.get("allstr").toString());
            // 拼接所有字符串
            StringBuilder sb = new StringBuilder();
            for (int i=0;i<allStrArr.size();i++) {
                sb.append(allStrArr.get(i).toString().split(":")[1].replace("\"",""));
            }
            result = sb.toString();
            logger.info("返回的所有文字集合为：{}", result);
        } catch (Throwable e) {
            logger.error("JSON转化失败");
            throw new ExecuteException("请求杭银ocr识别失败！");
        }
        return result;
    }

    /**
     * 根据杭银ocr返回结果获取所有字符集合
     *
     * @param data 杭银ocr返回结果
     * @return 识别文字
     */
    public static String getAllTextListByData(String data) {
        String result = "";
        try {
            JSONObject dataJson = JSONObject.parseObject(data);
            JSONArray allStrArr = JSONArray.parseArray(dataJson.get("allstr").toString());
            // 拼接所有字符串
            List<String> dataList = new ArrayList<>();
            for (int i=0;i<allStrArr.size();i++) {
                dataList.add(allStrArr.get(i).toString().split(":")[1].replace("\"",""));
            }
            result = JSON.toJSONString(dataList);
            logger.info("返回的所有文字集合为：{}", result);
        } catch (Throwable e) {
            logger.error("JSON转化失败");
        }
        return result;
    }

    /**
     * 根据杭银ocr返回结果获取查找字符所有的坐标
     *
     * @param data 杭银ocr返回结果
     * @param text 需要查找的文本
     * @return
     */
    public static List<PointMessage> getAllTextPointByData(String data, String text) {
        logger.info("传入的查找文本为：{}", text);
        List<PointMessage> points = new ArrayList<>();
        JSONObject dataJson = JSONObject.parseObject(data);
        JSONArray allStrArr = JSONArray.parseArray(dataJson.get("allstr").toString());
        // 拼接所有字符串
        StringBuilder allStr = new StringBuilder();
        Map textMap = new HashMap();
        for (int i=0;i<allStrArr.size();i++) {
            allStr.append(allStrArr.get(i).toString().split(":")[1].replace("\"",""));
            textMap.put(i, allStrArr.get(i).toString().split(":")[2].replace("[","").replace("]","").replace("}","").replace("\"",""));
        }
        logger.info("返回的所有文字字符串为：{}", allStr);
        logger.info("返回的所有文字坐标为：{}", textMap);
        // 根据需要查找的文本查找坐标
        List<Integer> indexs = new ArrayList<>();
        String s = allStr.toString();
        Integer fromIndex = 0;
        int i = s.indexOf(text, fromIndex);
        if (i != -1) {
            indexs.add(i);
            fromIndex = i + text.length();
            getAllIndexs(s, text, indexs, fromIndex);
        }
        for (Integer index : indexs) {
            logger.info("找到{}个符合的文字", indexs.size());
            Integer startIndex = index;
            Integer endIndex = index + text.length() - 1;;
            // 计算中心坐标
            points.add(getPoints(textMap.get(startIndex).toString(), textMap.get(endIndex).toString()));
        }
        return points;
    }

    /**
     * 获取所有下标结合
     *
     * @param s 字符串
     * @param text 查找的字符串
     * @param indexs 下标列表
     * @param fromIndex 首下标
     */
    private static void getAllIndexs(String s, String text, List<Integer> indexs, Integer fromIndex) {
        int i = s.indexOf(text, fromIndex);
        if (i != -1) {
            indexs.add(i);
            fromIndex = i + text.length();
            getAllIndexs(s, text, indexs, fromIndex);
        }
    }

    /**
     * 根据开始结束坐标计算中心坐标
     *
     * @param startPoint 开始坐标
     * @param endPoint 结束坐标
     * @return 中心坐标
     */
    private static PointMessage getPoints(String startPoint, String endPoint) {
        String[] startPointSplit = startPoint.split(",");
        String[] endPointSplit = endPoint.split(",");
        Integer x = Integer.parseInt(startPointSplit[0]) + (Integer.parseInt(endPointSplit[0])
                + Integer.parseInt(endPointSplit[2]) - Integer.parseInt(startPointSplit[0])) / 2;
        Integer y = Integer.parseInt(startPointSplit[1]) + (Integer.parseInt(endPointSplit[1])
                + Integer.parseInt(endPointSplit[2]) - Integer.parseInt(startPointSplit[1])) / 2;
        PointMessage point = new PointMessage(x, y, true);
        return point;
    }
}
