package com.kingdee.eas.custom.integration.feishu.app;

import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonParser;
import com.kingdee.bos.BOSException;
import com.kingdee.bos.Context;
import com.kingdee.bos.dao.IObjectPK;
import com.kingdee.bos.dao.IObjectValue;
import com.kingdee.bos.dao.ormapping.ObjectUuidPK;
import com.kingdee.bos.metadata.entity.SelectorItemCollection;
import com.kingdee.eas.base.permission.UserInfo;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.custom.integration.feishu.*;
import com.kingdee.eas.custom.integration.feishu.bizEnum.*;
import com.kingdee.shr.base.syssetting.BaseItemException;
import com.kingdee.shr.base.syssetting.api.bean.SHRCodingRule;
import com.kingdee.shr.base.syssetting.util.NumberRuleHelper;
import com.kingdee.util.DateTimeUtils;
import com.lark.oapi.Client;
import com.lark.oapi.core.utils.Jsons;
import com.lark.oapi.service.approval.v4.model.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import java.nio.charset.StandardCharsets;
import java.sql.Time;
import java.text.MessageFormat;
import java.util.*;

/**
 * 飞书审批实例
 */
public class FeishuApprovalInstanceControllerBean extends AbstractFeishuApprovalInstanceControllerBean {
    private static Logger logger = Logger.getLogger(FeishuApprovalInstanceControllerBean.class);

    /**
     * 新增
     *
     * @param ctx
     * @param model
     * @return
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected IObjectPK _addnew(Context ctx, IObjectValue model) throws BOSException, EASBizException {
        FeishuApprovalInstanceInfo feishuApprovalInstanceInfo = (FeishuApprovalInstanceInfo) model;
        feishuApprovalInstanceInfo.setBizDate(DateTimeUtils.truncateDate(new Date()));
        String number = feishuApprovalInstanceInfo.getNumber();
        if (StringUtils.isBlank(number)) {
            try {
                SHRCodingRule shrCodingRule = NumberRuleHelper.getCodingNumber(ctx, feishuApprovalInstanceInfo, "00000000-0000-0000-0000-000000000000CCE7AED4");
                feishuApprovalInstanceInfo.setNumber(shrCodingRule.getCodingRuleNumber());
            } catch (Exception e) {
                e.printStackTrace();
                throw new BOSException("生成飞书审批实例编码失败，请检查规则定义是否存在 : " + e.getMessage());
            }
        }
        //重置状态
        feishuApprovalInstanceInfo.setSyncStatus(SyncStatusEnum.UNSYNC);
        IObjectPK iObjectPK = super._addnew(ctx, model);
        try {
            //同步飞书审批实例
            syncApprovalInstance(ctx, iObjectPK.toString());
        } catch (Exception e) {
            logger.error("同步飞书审批实例失败: " + e.getMessage(), e);
        }
        return iObjectPK;

    }

    @Override
    protected void _update(Context ctx, IObjectPK pk, IObjectValue model) throws BOSException, EASBizException {
        FeishuApprovalInstanceInfo feishuApprovalInstanceInfo = (FeishuApprovalInstanceInfo) model;
        //重置状态
        feishuApprovalInstanceInfo.setSyncStatus(SyncStatusEnum.UNSYNC);
        super._update(ctx, pk, model);
        try {
            //同步飞书审批实例
            syncApprovalInstance(ctx, pk.toString());
        } catch (Exception e) {
            logger.error("同步飞书审批实例失败: " + e.getMessage(), e);
        }
    }

    /**
     * 同步飞书审批实例
     *
     * @param ctx
     * @param billId
     * @throws BOSException
     * @throws EASBizException
     */
    @Override
    protected void _syncApprovalInstance(Context ctx, String billId) throws BOSException, EASBizException {
        logger.info("同步飞书审批实例开始, billId: " + billId);

        //获取默认配置
        IFeishuConfig iFeishuConfig = FeishuConfigFactory.getLocalInstance(ctx);
        FeishuConfigCollection defaultConfigs = iFeishuConfig.getDefaultConfigs();
        if (defaultConfigs.isEmpty()) {
            throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{"未匹配到默认飞书应用配置！"});
        }
        FeishuConfigInfo feishuConfigInfo = defaultConfigs.get(0);
        if (!feishuConfigInfo.isStartProcessPush()) {
            logger.error("同步飞书审批实例 不推送, billId: " + billId);
            return;
        }
        SelectorItemCollection sic = new SelectorItemCollection();
        sic.add("*");
        sic.add("user.number");
        sic.add("user.feishuUserId");
        sic.add("approval.approvalCode");
        sic.add("title.*");
        sic.add("title.entrys.*");
        sic.add("taskList.*");
        sic.add("taskList.user.number");
        sic.add("taskList.user.feishuUserId");
        sic.add("taskList.title.*");
        sic.add("taskList.title.entrys.*");
        sic.add("taskList.nodeName.*");
        sic.add("taskList.nodeName.entrys.*");
        sic.add("forms.name.*");
        sic.add("forms.name.entrys.*");
        sic.add("forms.value.*");
        sic.add("forms.value.entrys.*");

        //审批定义
        FeishuApprovalInstanceInfo approvalInstanceInfo = getFeishuApprovalInstanceInfo(ctx, new ObjectUuidPK(billId), sic);
        //审批定义code
//        String number = approvalInstanceInfo.getNumber();
//        if (StringUtils.isBlank(number)) {
//            throw new BaseItemException(BaseItemException.CUSTOM_EXCEPTION, new Object[]{"审批定义code为空！"});
//        }

        SelectorItemCollection updateSic = new SelectorItemCollection();
        updateSic.add("syncStatus");
        updateSic.add("syncResult");
        try {
            //请求创建审批定义
            CreateExternalInstanceResp result = execExternalInstance(feishuConfigInfo, approvalInstanceInfo);

            // 处理服务端错误
            if (result.success()) {
                CreateExternalInstanceRespBody data = result.getData();
                // 业务数据处理
                logger.info("同步审批实例请求成功: " + Jsons.DEFAULT.toJson(data));
                approvalInstanceInfo.setSyncStatus(SyncStatusEnum.SUCCESS);
                approvalInstanceInfo.setSyncResult(result.getMsg());
            } else {
                //请求失败
                approvalInstanceInfo.setSyncStatus(SyncStatusEnum.FAIL);
                String msgFormat = "错误码: {0}\n报错信息: {1}\n完整错误信息: {2}";
                String error = result.getError().getTroubleshooter();
                if (StringUtils.isNotBlank(error) && error.length() > 512) {
                    error = error.substring(0, 512);
                }
                approvalInstanceInfo.setSyncResult(MessageFormat.format(msgFormat, result.getCode(), result.getMsg(), error));
                logger.info(String.format("创建审批定义请求失败: code:%s,msg:%s,reqId:%s, resp:%s",
                        result.getCode(), result.getMsg(), result.getRequestId(), Jsons.createGSON(true, false).toJson(JsonParser.parseString(new String(result.getRawResponse().getBody(), StandardCharsets.UTF_8)))));
            }
        } catch (Exception e) {
            e.printStackTrace();
            //请求失败
            approvalInstanceInfo.setSyncStatus(SyncStatusEnum.FAIL);
            approvalInstanceInfo.setSyncResult(e.getMessage());
            //throw new BOSException(e);
        }
        //更新
        updatePartial(ctx, approvalInstanceInfo, updateSic);
    }

    /**
     * 执行请求飞书同步三方实例接口
     *
     * @param feishuConfigInfo
     * @param approvalInstanceInfo
     * @return
     * @throws Exception
     */
    private CreateExternalInstanceResp execExternalInstance(
            FeishuConfigInfo feishuConfigInfo,
            FeishuApprovalInstanceInfo approvalInstanceInfo
    ) throws Exception {
        // 构建client
        Client client = Client.newBuilder(feishuConfigInfo.getAppID(), feishuConfigInfo.getAppSecret()).build();
        //构建请求体
        CreateExternalInstanceReq req = getCreateExternalInstanceReq(approvalInstanceInfo);
        logger.error("飞书同步三方实例请求参数: " + JSONObject.toJSONString(req));
        // 发起请求
        return client.approval().v4().externalInstance().create(req);
    }

    /**
     * 构建请求体
     *
     * @return
     */
    private CreateExternalInstanceReq getCreateExternalInstanceReq(FeishuApprovalInstanceInfo approvalInstanceInfo) throws BOSException {
        //多语言资源
        List<FeishuI18nResourcesInfo> resourcesList = new LinkedList<>();

        //审批定义
        FeishuApprovalsInfo approval = approvalInstanceInfo.getApproval();
        if (approval == null) {
            throw new BOSException("审批定义为空!");
        }
        //审批定义Code
        String approvalCode = approval.getApprovalCode();
        if (StringUtils.isBlank(approvalCode)) {
            throw new BOSException("审批定义Code为空!");
        }
        //审批实例状态
        InstanceStatusEnum status = approvalInstanceInfo.getStatus();
        if (status == null) {
            throw new BOSException("审批实例状态为空!");
        }
        //PC 端的三方审批实例跳转链接
        String pcLink = approvalInstanceInfo.getPcLink();
        //移动端的三方审批实例跳转链接。
        String mobileLink = approvalInstanceInfo.getMobileLink();

        //审批展示名称。
        FeishuI18nResourcesInfo title = approvalInstanceInfo.getTitle();
        if (title == null) {
            throw new BOSException("审批展示名称为空!");
        }
        resourcesList.add(title);
        //审批发起人
        UserInfo user = approvalInstanceInfo.getUser();
        if (user == null) {
            throw new BOSException("审批发起人为空!");
        }
        //飞书用户id
        String feishuUserId = user.getString("feishuUserId");
        if (StringUtils.isBlank(feishuUserId)) {
            throw new BOSException("用户 [" + user.getNumber() + "]的飞书userId为空!");
        }

        //审批发起时间，Unix 毫秒时间戳
        Time startTime = approvalInstanceInfo.getStartTime();
        if (startTime == null) {
            throw new BOSException("审批发起时间为空!");
        }
        String startTimeStr = String.valueOf(startTime.getTime());

        //审批实例结束时间。未结束的审批为 0，Unix 毫秒时间戳。
        String endTimeStr = "0";
        Time endTime = approvalInstanceInfo.getEndTime();
        if (endTime != null) {
            endTimeStr = String.valueOf(endTime.getTime());
        }
        //审批实例最近更新时间，Unix 毫秒时间戳，
        Time updateTime = approvalInstanceInfo.getUpdateTime();
        if (updateTime == null) {
            throw new BOSException("审批实例最近更新时间为空!");
        }
        String updateTimeStr = String.valueOf(updateTime.getTime());

        //列表页打开审批实例的方式
        DisplayMethodEnum displayMethod = approvalInstanceInfo.getDisplayMethod();
        if (displayMethod == null) {
            throw new BOSException("列表页打开审批实例的方式为空!");
        }

        //更新方式
        InstanceUpdateModeEnum updateMode = approvalInstanceInfo.getUpdateMode();
        if (updateMode == null) {
            throw new BOSException("更新方式为空!");
        }
        //用户提交审批时填写的表单数据
        ExternalInstanceForm[] externalInstanceFormArray = getExternalInstanceFormArray(approvalInstanceInfo.getForms(), resourcesList);

        //任务列表
        ExternalInstanceTaskNode[] externalInstanceTaskNodeArray =
                getExternalInstanceTaskNodeArray(approvalInstanceInfo.getTaskList(), resourcesList);
        I18nResource[] i18nResourceArray = getI18nResourceArray(resourcesList);

        // 创建请求对象
        return CreateExternalInstanceReq.newBuilder()
                .externalInstance(ExternalInstance.newBuilder()
                        .approvalCode(approvalCode)//审批定义Code
                        .status(status.getValue())//审批实例状态
                        //审批实例扩展参数，JSON 格式，传值时需要压缩转义为字符串。单据编号通过传 business_key 参数来实现。
                        .extra("{\"business_key\":\"2026030501\",\"xxx\":\"xxx\"}")
                        .instanceId(approvalInstanceInfo.getInstanceId())//实例id
                        .links(ExternalInstanceLink.newBuilder()
                                .pcLink(pcLink)//PC 端的三方审批实例跳转链接。
                                .mobileLink(mobileLink)//移动端的三方审批实例跳转链接。
                                .build())
                        .title(title.getNumber())//审批展示名称
                        .form(externalInstanceFormArray)//用户提交审批时填写的表单数据
                        //userId(feishuUserId)//发起人
                        //.userName("@i18n@9")//发起人姓名
                        .openId(feishuUserId)//发起人
                        //.departmentId("")//todo 部门没有集成
                        //.departmentName("")
                        .startTime(startTimeStr)//审批发起时间
                        .endTime(endTimeStr)//审批实例结束时间。未结束的审批为 0
                        .updateTime(updateTimeStr)//审批实例最近更新时间
                        .displayMethod(displayMethod.getValue())//列表页打开审批实例的方式
                        .updateMode(updateMode.getValue())//更新方式
                        .taskList(externalInstanceTaskNodeArray)//任务列表
                        //.ccList(getCcNodeArray())//todo 抄送列表
                        .i18nResources(i18nResourceArray)
                        //单据托管
                        //.trusteeshipUrlToken("788981c886b1c28ac29d1e68efd60683d6d90dfce80938ee9453e2a5f3e9e306")
                        //.trusteeshipUserIdType("user_id")
//                        .trusteeshipUrls(TrusteeshipUrls.newBuilder()
//                                .formDetailUrl("https://#{your_domain}/api/form_detail")
//                                .actionDefinitionUrl("https://#{your_domain}/api/action_definition")
//                                .approvalNodeUrl("https://#{your_domain}/api/approval_node")
//                                .actionCallbackUrl("https://#{your_domain}/api/action_callback")
//                                .pullBusinessDataUrl("https://#{your_domain}/api/pull_business_data")
//                                .build())
//                        .trusteeshipCacheConfig(TrusteeshipInstanceCacheConfig.newBuilder()
//                                .formPolicy("DISABLE")
//                                .formVaryWithLocale(false)
//                                .formVersion("1")
//                                .build())
                        //.resourceRegion("cn")//资源所在地区， 内部统计用字段， 不需要填
                        .build())
                .build();
    }

    /**
     * 获取任务列表请求参数
     *
     * @return
     */
    private ExternalInstanceTaskNode[] getExternalInstanceTaskNodeArray(
            FeishuApprovalInstanceTaskListCollection taskList,
            List<FeishuI18nResourcesInfo> resourcesList
    ) throws BOSException {
        if (taskList == null || taskList.isEmpty()) {
            return new ExternalInstanceTaskNode[]{};
        } else {
            List<ExternalInstanceTaskNode> list = new ArrayList<ExternalInstanceTaskNode>();
            for (int i = 0; i < taskList.size(); i++) {
                FeishuApprovalInstanceTaskListInfo taskListInfo = taskList.get(i);
                //审批人
                UserInfo user = taskListInfo.getUser();
                if (user == null) {
                    throw new BOSException("审批人为空!");
                }
                //飞书用户id
                String feishuUserId = user.getString("feishuUserId");
                if (StringUtils.isBlank(feishuUserId)) {
                    throw new BOSException("用户 [" + user.getNumber() + "]的飞书userId为空!");
                }
                //审批任务名称
                FeishuI18nResourcesInfo title = taskListInfo.getTitle();
                if (title == null) {
                    throw new BOSException("审批任务名称为空!");
                }
                resourcesList.add(title);
                //PC 端的三方审批实例跳转链接
                String pcLink = taskListInfo.getPcLink();
                //移动端的三方审批实例跳转链接。
                String mobileLink = taskListInfo.getMobileLink();
                //任务状态
                TaskStatusEnum status = taskListInfo.getStatus();
                if (status == null) {
                    throw new BOSException("任务状态为空!");
                }
                //任务创建时间
                Time createTime = taskListInfo.getCreateTime();
                if (createTime == null) {
                    throw new BOSException("任务创建时间为空!");
                }
                String createTimeStr = String.valueOf(createTime.getTime());

                //任务完成时间
                String endTimeStr = "0";
                Time endTime = taskListInfo.getEndTime();
                if (endTime != null) {
                    endTimeStr = String.valueOf(endTime.getTime());
                }
                //任务最近更新时间，Unix 毫秒时间戳，
                Time updateTime = taskListInfo.getUpdateTime();
                if (updateTime == null) {
                    throw new BOSException("任务最近更新时间为空!");
                }
                String updateTimeStr = String.valueOf(updateTime.getTime());

                //审批中心列表页打开审批任务的方式。
                DisplayMethodEnum displayMethod = taskListInfo.getDisplayMethod();
                if (displayMethod == null) {
                    throw new BOSException("任务列表页打开审批实例的方式为空!");
                }
                //节点名称
                FeishuI18nResourcesInfo nodeName = taskListInfo.getNodeName();
//                if (nodeName == null) {
//                    throw new BOSException("任务节点名称为空!");
//                }
//                resourcesList.add(nodeName);

                ExternalInstanceTaskNode.Builder builder = ExternalInstanceTaskNode.newBuilder()
                        .taskId(taskListInfo.getTaskId())//审批实例内，审批任务的唯一标识，用于更新审批任务时定位数据。
                        .openId(feishuUserId)//审批人 openId
                        .title(title.getNumber())//审批任务名称
                        .links(ExternalInstanceLink.newBuilder()
                                .pcLink(pcLink)//PC 端的跳转链接。
                                .mobileLink(mobileLink)//移动端的跳转链接。
                                .build())
                        .status(status.getValue())//任务状态
                        .extra(taskListInfo.getExtra())//扩展字段。JSON 格式
                        .createTime(createTimeStr)//任务创建时间
                        .endTime(endTimeStr)//任务完成时间
                        .updateTime(updateTimeStr)//任务最近更新时间
                        //.actionContext("123456")//操作上下文。当用户操作审批时，回调请求中会包含该参数，用于传递该任务的上下文数据。
//                        .actionConfigs(new ActionConfig[]{
//                                ActionConfig.newBuilder()
//                                        .actionType("APPROVE")
//                                        .actionName("@i18n@5")
//                                        .isNeedReason(false)
//                                        .isReasonRequired(false)
//                                        .isNeedAttachment(false)
//                                        .build()
//                        })//任务级别的快捷审批操作配置。
                        .displayMethod(displayMethod.getValue())//审批中心列表页打开审批任务的方式。
                        .excludeStatistics(taskListInfo.isExcludeStatistics())//三方审批任务是否不纳入效率统计
                        .generateType(taskListInfo.getGenerateType());//任务生成类型
                if (StringUtils.isNotBlank(taskListInfo.getNodeId())) {
                    builder.nodeId(taskListInfo.getNodeId())//审批节点 ID
                            .nodeName(nodeName.getNumber());//节点名称
                }
                list.add(builder.build());
            }
            return list.toArray(new ExternalInstanceTaskNode[list.size()]);
        }
    }

    /**
     * 获取用户提交审批时填写的表单数据
     * 用于所有审批列表中展示。可传多个值，最多展示前 3 个，长度不超过 2048 字符。
     *
     * @return
     */
    private ExternalInstanceForm[] getExternalInstanceFormArray(
            FeishuApprovalInstanceFormCollection forms,
            List<FeishuI18nResourcesInfo> resourcesList) {

        List<ExternalInstanceForm> externalInstanceForms = new ArrayList();
        if (forms == null) {
            return new ExternalInstanceForm[0];
        }
        for (int i = 0; i < forms.size(); i++) {
            FeishuApprovalInstanceFormInfo feishuApprovalInstanceFormInfo = forms.get(i);
            FeishuI18nResourcesInfo name = feishuApprovalInstanceFormInfo.getName();
            resourcesList.add(name);
            FeishuI18nResourcesInfo value = feishuApprovalInstanceFormInfo.getValue();
            resourcesList.add(value);
            externalInstanceForms.add(ExternalInstanceForm.newBuilder()
                    .name(name.getNumber())
                    .value(value.getNumber())
                    .build());
        }
        return externalInstanceForms.toArray(new ExternalInstanceForm[externalInstanceForms.size()]);
    }


    /**
     * 获取抄送列表请求参数
     *
     * @return
     */
    private CcNode[] getCcNodeArray() {
        return new CcNode[]{
                CcNode.newBuilder()
                        .ccId("123456")
                        .userId("3f16gecg")
                        .openId("")
                        .links(ExternalInstanceLink.newBuilder()
                                .pcLink("http://www.earthcn.cn:6888/shr/api/feishu/?redirect=%2fdynamic.do%3fuipk%3dshr.perself.homepage.new%26inFrame%3dtrue%26appId%3dcli_a914295c8bf85bb5")
                                .mobileLink("http://www.earthcn.cn:6888/shr/api/feishu/?redirect=https%3a%2f%2fmbos.kdeascloud.com%2fmbos%2fpage%2floadPage%3fappid%3d10036%26eid%3dK172K145K108K99K127%26path%3dlczs2%26name%3dlczshome.navui%26appId%3dcli_a914295c8bf85bb5")
                                .build())
                        .readStatus("READ")
                        .extra("{\"xxx\":\"xxx\"}")
                        .title("xxx")
                        .createTime("1556468012678")
                        .updateTime("1556468012678")
                        .displayMethod("BROWSER")
                        .build()
        };
    }

    /**
     * 获取多语言资源
     *
     * @return
     */
    private I18nResource[] getI18nResourceArray(List<FeishuI18nResourcesInfo> resourcesList) {
        List<I18nResourceText> i18nResourceTexts = new ArrayList();
        for (int i = 0; i < resourcesList.size(); i++) {
            FeishuI18nResourcesInfo resource = resourcesList.get(i);
            if (resource != null) {
                Map<LocaleEnum, I18nResourceText> resourcesMap = new HashMap<LocaleEnum, I18nResourceText>();

                FeishuI18nResourcesEntryCollection resourcesEntrys = resource.getEntrys();
                for (int j = 0; j < resourcesEntrys.size(); j++) {
                    FeishuI18nResourcesEntryInfo entryInfo = resourcesEntrys.get(j);
                    //语言
                    LocaleEnum locale = entryInfo.getLocale();
                    //文本
                    String value = entryInfo.getValue();
                    resourcesMap.put(locale, I18nResourceText.newBuilder()
                            .key(resource.getNumber())
                            .value(value)
                            .build());
                }
                if (resourcesMap.get(LocaleEnum.ZHCN) != null) {
                    i18nResourceTexts.add(resourcesMap.get(LocaleEnum.ZHCN));
                }
            }
        }

        I18nResourceText[] i18nResourceTextArray = i18nResourceTexts.toArray(new I18nResourceText[i18nResourceTexts.size()]);
        //国际化资源
        I18nResource[] i18nResources = {
                I18nResource.newBuilder()
                        .locale(LocaleEnum.ZHCN_VALUE)//中文
                        .texts(i18nResourceTextArray).isDefault(true)
                        .build()
        };
        return i18nResources;
    }
}