package com.seeyon.apps.esign.po.signer;

import com.seeyon.aicloud.common.JsonUtils;
import com.seeyon.apps.esign.config.EsignConfigProvider;
import com.seeyon.apps.esign.constants.EsignApiUrl;
import com.seeyon.apps.esign.constants.EsignConfigConstants;
import com.seeyon.apps.esign.po.esignapi.EsignApiHeader;
import com.seeyon.apps.esign.po.esignapi.EsignBaseResp;
import com.seeyon.apps.esign.po.signfield.NormalSignFieldConfig;
import com.seeyon.apps.esign.po.signfield.SignField;
import com.seeyon.apps.esign.po.signfield.SignFieldPosition;
import com.seeyon.apps.esign.service.TokenCacheManager;
import com.seeyon.apps.esign.utils.HttpClient;
import com.seeyon.ctp.common.AppContext;
import org.apache.commons.lang.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 默认签署方构建器
 * 负责根据签署方类型（个人/机构/法定代表人）构建 e 签宝对接所需的 Signer 对象
 *
 * @author seeyon
 */
public class DefaultSignerBuilder implements SignerBuilder {

    /** 配置提供者 */
    private final EsignConfigProvider esignConfigProvider = EsignConfigProvider.getInstance();

    /** Token 缓存管理器 */
    private final TokenCacheManager tokenCacheManager = (TokenCacheManager) AppContext.getBean("tokenCacheManager");

    // 常量定义
    private static final String NOTICE_TYPE_SMS = "1";
    private static final String ORG_ID_CARD_TYPE = "CRED_ORG_USCC";
    private static final String ACROSS_PAGE_MODE_ALL = "ALL";
    private static final String PARTY_A = "甲方";
    private static final String PARTY_B = "乙方";
    private static final String ANTI_COUNTERFEIT_PARTY = "防伪章签署方";
    private static final int SIGN_FIELD_STYLE_NORMAL = 1;
    private static final int SIGN_FIELD_STYLE_ACROSS_PAGE = 2;

    @Override
    public Signer build(List<String> fileIds, List<Object> keywordPos, SignParty party, String appId) {
        // 校验入参
        validateSignParty(party);

        SignerType signerType = party.getSignerType();
        if (SignerType.PERSON == signerType) {
            return buildPersonSigner(fileIds, keywordPos, party, appId);
        } else if (SignerType.ORG == signerType || SignerType.LP == signerType) {
            return buildOrgSigner(fileIds, keywordPos, party, appId);
        } else {
            throw new IllegalArgumentException("不支持的签署方类型：" + signerType);
        }
    }

    /**
     * 构建个人签署方
     */
    private Signer buildPersonSigner(List<String> fileIds, List<Object> keywordPos, SignParty party, String appId) {
        PersonInfo personInfo = party.getPersonInfo();
        if (personInfo == null) {
            throw new IllegalStateException("个人签署方缺少 PersonInfo 信息");
        }

        Signer signer = new Signer();
        signer.setSignerType(0);
        signer.setSignConfig(buildSignOrderConfig(party.getSignOrder()));

        // 非自动签署，设置通知信息和个人信息
        if (!party.getAutoSign()) {
            signer.setNoticeConfig(buildNoticeConfig());
            signer.setPsnSignerInfo(buildPersonSignerInfo(personInfo));
        }

        signer.setSignFields(buildSignFields(fileIds, keywordPos, party, appId));
        return signer;
    }

    /**
     * 构建机构/法定代表人签署方
     */
    private Signer buildOrgSigner(List<String> fileIds, List<Object> keywordPos, SignParty party, String appId) {
        OrgInfo orgInfo = party.getOrgInfo();
        Signer signer = new Signer();

        // 设置签署方类型
        signer.setSignerType(SignerType.ORG == party.getSignerType() ? 1 : 2);
        signer.setSignConfig(buildSignOrderConfig(party.getSignOrder()));

        // 非自动签署，设置通知信息和机构信息
        if (!party.getAutoSign() && orgInfo != null) {
            signer.setNoticeConfig(buildNoticeConfig());
            signer.setOrgSignerInfo(buildOrgSignerInfo(orgInfo));
        }else {
            signer.setOrgSignerInfo(buildOrgSignerInfoWithNoPsn(orgInfo));
        }
        signer.setSignFields(buildSignFields(fileIds, keywordPos, party, appId));
        return signer;
    }

    /**
     * 构建签署区集合（核心逻辑）
     */
    private List<SignField> buildSignFields(List<String> fileIds, List<Object> keywordPos, SignParty party, String appId) {
        List<SignField> signFields = new ArrayList<>();

        for (String fileId : fileIds) {
            if (party.getFreeSign()) {
                // 自由签署模式
                signFields.add(buildFreeSignField(fileId, party));
            } else {
                // 关键字定位 + 骑缝章 + 防伪章模式
                buildNormalSignFields(signFields, fileId, keywordPos, party, appId);
            }
        }

        return signFields;
    }

    /**
     * 构建普通关键字定位签署区（含骑缝章、防伪章）
     */
    private void buildNormalSignFields(List<SignField> signFields, String fileId, List<Object> keywordPos,
                                       SignParty party, String appId) {
        // 防伪章使用固定坐标，不走关键字定位
        if (ANTI_COUNTERFEIT_PARTY.equals(party.getPartyId())) {
            addAntiCounterfeitSignFields(signFields, fileId, party, appId);
            return;
        }

        // 根据签署方自带的关键字提取位置
        List<SignFieldPosition> positions = extractPosition(keywordPos, party.getSignKeyword());

        // 机构签署 + 骑缝签署，追加骑缝位置
        if (!positions.isEmpty() && !SignerType.PERSON.equals(party.getSignerType()) && party.getSignAcrossPage()) {
            SignFieldPosition acrossPagePosition = buildAcrossPagePosition(party);
            if (acrossPagePosition != null) {
                positions.add(acrossPagePosition);
            }
        }

        // 生成签署区
        for (SignFieldPosition position : positions) {
            signFields.add(buildNormalSignField(fileId, party, position));
        }
    }

    /**
     * 提取关键字坐标位置
     */
    private List<SignFieldPosition> extractPosition(List<Object> positions, String keyword) {
        List<SignFieldPosition> posList = new ArrayList<>();
        if (StringUtils.isBlank(keyword) || positions == null || positions.isEmpty()) {
            return posList;
        }

        for (Object obj : positions) {
            Map<String, Object> posMap = (Map<String, Object>) obj;
            // 匹配关键字且搜索成功
            if (Boolean.TRUE.equals(posMap.get("searchResult")) && keyword.equals(posMap.get("keyword"))) {
                parseCoordinatePositions(posList, posMap);
                return posList;
            }
        }
        return posList;
    }

    /**
     * 解析坐标信息
     */
    private void parseCoordinatePositions(List<SignFieldPosition> posList, Map<String, Object> posMap) {
        Object[] posArray = (Object[]) posMap.get("positions");
        for (Object posObj : posArray) {
            Map<String, Object> coordMap = (Map<String, Object>) posObj;
            Object[] coords = (Object[]) coordMap.get("coordinates");

            for (Object coord : coords) {
                Map<String, Object> tempMap = (Map<String, Object>) coord;
                SignFieldPosition position = new SignFieldPosition();
                position.setPositionPage(String.valueOf(coordMap.get("pageNum")));
                position.setPositionX(safeToFloat(tempMap.get("positionX")) + 160f);
                position.setPositionY(safeToFloat(tempMap.get("positionY")));
                posList.add(position);
            }
        }
    }

    /**
     * 构建防伪章签署区
     */
    private void addAntiCounterfeitSignFields(List<SignField> signFields, String fileId, SignParty party, String appId) {
        int totalPage = getFileTotalPage(fileId, appId);
        for (int page = 1; page <= totalPage; page++) {
            SignFieldPosition position = new SignFieldPosition();
            position.setPositionPage(String.valueOf(page));
            position.setPositionX(549f);
            position.setPositionY(830f);
            signFields.add(buildNormalSignField(fileId, party, position));
        }
    }

    /**
     * 构建自由签署模式签署区
     */
    private SignField buildFreeSignField(String fileId, SignParty party) {
        NormalSignFieldConfig config = new NormalSignFieldConfig();
        config.setAssignedSealId(party.getSealId());
        config.setFreeMode(true);
        config.setAutoSign(false);
        config.setAdaptableSignFieldSize(true);

        SignField field = new SignField();
        field.setSignFieldType(0);
        field.setNormalSignFieldConfig(config);
        field.setFileId(fileId);
        return field;
    }

    /**
     * 构建普通签署区
     */
    private SignField buildNormalSignField(String fileId, SignParty party, SignFieldPosition position) {
        NormalSignFieldConfig config = new NormalSignFieldConfig();
        config.setSignFieldPosition(position);
        config.setAssignedSealId(party.getSealId());
        config.setAutoSign(party.getAutoSign());
        config.setSignFieldStyle(ACROSS_PAGE_MODE_ALL.equals(position.getAcrossPageMode())
                ? SIGN_FIELD_STYLE_ACROSS_PAGE : SIGN_FIELD_STYLE_NORMAL);

        SignField field = new SignField();
        field.setSignFieldType(0);
        field.setNormalSignFieldConfig(config);
        field.setFileId(fileId);
        return field;
    }

    /**
     * 构建骑缝章位置
     */
    private SignFieldPosition buildAcrossPagePosition(SignParty party) {
        SignFieldPosition position = new SignFieldPosition();
        position.setAcrossPageMode(ACROSS_PAGE_MODE_ALL);
        if (PARTY_A.equals(party.getPartyId())) {
            position.setPositionY(520f);
        } else if (PARTY_B.equals(party.getPartyId())) {
            position.setPositionY(720f);
        }
        return null;
    }

    /**
     * 构建签署顺序配置
     */
    private Map<String, Object> buildSignOrderConfig(Integer signOrder) {
        return mapOf("signOrder", signOrder);
    }

    /**
     * 构建通知配置
     */
    private Map<String, Object> buildNoticeConfig() {
        return mapOf("noticeTypes", NOTICE_TYPE_SMS);
    }

    /**
     * 构建个人签署信息
     */
    private Map<String, Object> buildPersonSignerInfo(PersonInfo psn) {
        return mapOf(
                "psnAccount", psn.getPhone(),
                "psnInfo", mapOf(
                        "psnName", psn.getName(),
                        "psnIDCardNum", psn.getIdCardNo(),
                        "psnIDCardType", psn.getIdCardType()
                )
        );
    }

    /**
     * 构建机构签署信息
     */
    private Map<String, Object> buildOrgSignerInfo(OrgInfo org) {
        return mapOf(
                "orgName", org.getOrgName(),
                "orgIg",org.getOrgId(),
                "orgInfo", mapOf(
                        "legalRepName", org.getLegalName(),
                        "legalRepIDCardNum", org.getLegalIdCardNo(),
                        "orgIDCardNum", org.getOrgCode(),
                        "orgIDCardType", ORG_ID_CARD_TYPE
                ),
                "transactorInfo", mapOf(
                        "psnAccount", org.getTransactor().getPhone(),
                        "psnInfo", mapOf(
                                "psnName", org.getTransactor().getName(),
                                "psnIDCardNum", org.getTransactor().getIdCardNo()
                        )
                )
        );
    }

    /**
     * 构建机构签署信息
     */
    private Map<String, Object> buildOrgSignerInfoWithNoPsn(OrgInfo org) {
        return mapOf(
                "orgName", org.getOrgName(),
                 "orgIg",org.getOrgId(),
                "orgInfo", mapOf(
                        "legalRepName", org.getLegalName(),
                        "legalRepIDCardNum", org.getLegalIdCardNo(),
                        "orgIDCardNum", org.getOrgCode(),
                        "orgIDCardType", ORG_ID_CARD_TYPE
                )
        );
    }

    /**
     * 查询文件总页数
     */
    private Integer getFileTotalPage(String fileId, String appId) {
        try {
            EsignApiHeader header = EsignApiHeader.build()
                    .appId(appId)
                    .token(tokenCacheManager.getToken(appId));

            String host = esignConfigProvider.getBizConfigByKey(EsignConfigConstants.ESIGN_HOST);
            String url = host + EsignApiUrl.QUERY_FILEUPLOADSTATUS + "/" + fileId;

            String respStr = HttpClient.httpGet(url, header.convert2Headers(), "UTF-8");
            EsignBaseResp resp = JsonUtils.parseObject(respStr, EsignBaseResp.class);

            if (!"0".equals(String.valueOf(resp.getCode()))) {
                throw new RuntimeException("查询文件上传状态失败：" + resp.getMessage());
            }

            Map<String, Object> data = (Map<String, Object>) resp.getData();
            Object pageCount = data.get("fileTotalPageCount");
            return pageCount == null ? 10 : Integer.parseInt(String.valueOf(pageCount));
        } catch (Exception e) {
            throw new RuntimeException("获取文件页数异常", e);
        }
    }

    /**
     * 安全转换为 Float
     */
    private Float safeToFloat(Object val) {
        if (val == null) {
            return 0f;
        }
        return val instanceof Number ? ((Number) val).floatValue() : Float.parseFloat(val.toString());
    }

    /**
     * 校验签署方参数
     */
    private void validateSignParty(SignParty party) {
        if (party == null) {
            throw new IllegalArgumentException("签署方信息不能为空");
        }
        if (party.getSignerType() == null) {
            throw new IllegalArgumentException("签署方类型不能为空");
        }
    }

    /**
     * 快速构建 Map
     */
    private Map<String, Object> mapOf(Object... keyValues) {
        if (keyValues.length % 2 != 0) {
            throw new IllegalArgumentException("键值对数量必须为偶数");
        }
        Map<String, Object> map = new HashMap<>();
        for (int i = 0; i < keyValues.length; i += 2) {
            map.put((String) keyValues[i], keyValues[i + 1]);
        }
        return map;
    }
}