package com.malk.service.aliwork.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.malk.server.aliwork.YDConf;
import com.malk.server.aliwork.YDParam;
import com.malk.server.common.McException;
import com.malk.server.dingtalk.DDR_New;
import com.malk.service.aliwork.YDClient;
import com.malk.service.aliwork.YDService;
import com.malk.utils.UtilMap;
import com.malk.utils.UtilString;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class YDServiceImpl implements YDService {

    @Autowired
    private YDClient ydClient;

    /**
     * 操作数据 [异步] - 审批通过立即更新, 会无效
     */
    @Async
    @SneakyThrows
    @Override
    public Object operateData(YDParam ydParam, YDConf.FORM_OPERATION type) {
        Thread.sleep(3000);
        return ydClient.operateData(ydParam, type);
    }

    @Async
    @SneakyThrows
    @Override
    public Object operateData2(Map data, Map update, YDParam ydParam, YDConf.FORM_OPERATION type) {

        // prd 9.10 更新报销单, 关联到发票:: todo 宜搭服务注册拿不到系统默认字段, 先查询解决
        if (data.containsKey("aUuid")) {
            Thread.sleep(3000);
            List<Map> process = (List<Map>) ydClient.queryData(YDParam.builder()
                    .formUuid(data.get("aFormUuid").toString())
                    .searchFieldJson(JSON.toJSONString(UtilMap.map("textField_lmewsobs", data.get("aUuid"))))
                    .build(), YDConf.FORM_QUERY.retrieve_search_form).getData();

            update.put(data.get("aCompId"),
                    Arrays.asList(UtilMap.map("appType, formType, instanceId, formUuid, title",
                            "APP_FKRK7Y94DPI1S9DV1605", "process", process.get(0).get("formInstanceId"), data.get("aFormUuid"), process.get(0).get("title"))));
            ydParam.setUpdateFormDataJson(JSON.toJSONString(update));
        }
        return ydClient.operateData(ydParam, type);
    }


    /**
     * 子表全部数据获取, 最大分页为50 [可考虑中间表思路]
     */
    @Override
    public List<Map> queryDetails(YDParam ydParam) {
        return _queryDetails(ydParam, new ArrayList<>());
    }

    // 递归查询 todo 如果查询中, totalCount 发生变化, 就会进入死循环
    private List<Map> _queryDetails(YDParam ydParam, List<Map> details) {
        ydParam.setPageSize(50);
        DDR_New ddr_new = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_details);
        details.addAll((List<Map>) ddr_new.getData());
        if (ddr_new.getTotalCount() != details.size()) {
            ydParam.setPageNumber(ydParam.getPageNumber() + 1);
            _queryDetails(ydParam, details);
        }
        return details;
    }

    /**
     * 查询全部 [主表]
     */
    @Override
    public List<Map> queryAllFormData(YDParam ydParam) {
        float pageSize = YDConf.PAGE_SIZE_LIMIT;
        // 查询数据量 [todo 先查询100, 再进行分页, 避免无效查询多一次]; 2. 直接返回formData, 兼容实例ID
        ydParam.setPageSize(1);
        long totalCount = ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_form).getTotalCount();
        // 轮询累计数据
        List<Map> dataList = new ArrayList<>();
        ydParam.setCurrentPage(1);
        ydParam.setPageSize((int) pageSize);
        for (int page = 1; page <= Math.ceil(totalCount / pageSize); page++) {
            ydParam.setCurrentPage(page);
            dataList.addAll((List<Map>) ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_form).getData());
        }
        return dataList;
    }

    // ppExt: 查询100后再进分页, 且转为formData内数据, todo Process待完成
    @Override
    public List<Map> queryFormData_all_advance(YDParam ydParam, YDConf.FORM_QUERY type) {

        float pageSize = YDConf.PAGE_SIZE_LIMIT;

        ydParam.setPageNumber(1); // todo 分页
        ydParam.setPageSize((int) pageSize);
        DDR_New ddr_new = ydClient.queryData(ydParam, type);

        List<Map> dataList = new ArrayList<>();
        dataList.addAll((List<Map>) ddr_new.getData());

        long totalCount = ddr_new.getTotalCount(); // todo 大于1扣减
        if (totalCount > 100) {
            for (int page = 2; page <= Math.ceil(totalCount / pageSize); page++) {
                ydParam.setPageNumber(page);
                dataList.addAll((List<Map>) ydClient.queryData(ydParam, type).getData());
            }
        }
        return dataList.stream().map(item -> {
            Map formData = (Map) item.get("formData");
            formData.put("instanceId", item.get("formInstanceId"));
            formData.put("formInstanceId", item.get("formInstanceId"));
            return formData;
        }).collect(Collectors.toList());
    }

    @Override
    public List<Map> queryFormData_all(YDParam YDParam) {
        List<Map> dataList = queryAllFormData(YDParam);
        return dataList.stream().map(item -> {
            Map formData = (Map) item.get("formData");
            formData.put("instanceId", item.get("formInstanceId"));
            formData.put("formInstanceId", item.get("formInstanceId"));
            return formData;
        }).collect(Collectors.toList());
    }

    /**
     * 查询宜搭数据
     */
    @Override
    public List queryDataList_FormData(String formUuid, Map conditions) {
        conditions = UtilMap.empty(conditions);
        List<Map> dataList = (List<Map>) ydClient.queryData(YDParam.builder()
                        .formUuid(formUuid)
                        .searchFieldJson(JSON.toJSONString(conditions)).build(),
                YDConf.FORM_QUERY.retrieve_search_form).getData();
        return dataList.stream().map(item -> {
            Map formData = (Map) item.get("formData");
            formData.put("instanceId", item.get("formInstanceId"));
            return formData;
        }).collect(Collectors.toList());
    }

    /**
     * 查询宜搭数据 [精确匹配]
     */
    @Override
    public List queryFormData(String formUuid, String conditions) {
        List<Map> dataList = (List<Map>) ydClient.queryData(YDParam.builder()
                        .formUuid(formUuid)
                        .searchCondition(conditions).build(),
                YDConf.FORM_QUERY.retrieve_list).getData();
        return dataList.stream().map(item -> {
            Map formData = (Map) item.get("formData");
            formData.put("instanceId", item.get("formInstanceId"));
            return formData;
        }).collect(Collectors.toList());
    }

    /**
     * 字段复制
     */
    @Override
    public Object copyFormData(Map data) {

        McException.assertParamException_Null(data, "formData, formUuid, processCode, compIds");
        Map compIds = (Map) JSON.parse(String.valueOf(data.get("compIds")));
        McException.assertParamException_Null(compIds, "cur, src"); // compIds 包含全部组件
        Map formData = (Map) JSON.parse(String.valueOf(data.get("formData")));

        String[] compIds_cur = UtilMap.getString(compIds, "cur").split(", ");
        String[] compIds_src = UtilMap.getString(compIds, "src").split(", ");
        McException.assertAccessException(compIds_cur.length != compIds_src.length, "主表的字段数量不一致, 请检查配置");

        // 目标表数据处理
        Map dataForm = new HashedMap();
        for (int i = 0; i < compIds_cur.length; i++) {
            String compId_cur = compIds_cur[i];
            String compId_src = compIds_src[i];
            // 子表的顺序要保持一致
            if (compId_cur.contains("tableField_") || compId_src.contains("tableField_")) {
                boolean isAssert = (compId_cur.contains("tableField_") && !compId_src.contains("tableField_")) || (!compId_cur.contains("tableField_") && compId_src.contains("tableField_"));
                McException.assertAccessException(isAssert, "子表组件类型不一致, 请检查配置");
                String[] compIds_cur_detail = UtilMap.getString(compIds, compId_cur + "_cur").split(", ");
                String[] compIds_src_detail = UtilMap.getString(compIds, compId_src + "_src").split(", ");
                McException.assertAccessException(compIds_cur_detail.length != compIds_src_detail.length, "子表的字段数量不一致, 请检查配置");
                // 子表数据处理
                List<Map> details = new ArrayList<>();
                for (Map detail : (List<Map>) UtilMap.getList(formData, compId_cur)) {
                    Map rowData = new HashedMap();
                    // 子表组件处理
                    for (int j = 0; j < compIds_cur_detail.length; j++) {
                        String compId_cur_detail = compIds_cur_detail[j];
                        String compId_src_detail = compIds_src_detail[j];
                        rowData.put(compId_src_detail, YDConf.getDataByCompId(detail, compId_cur_detail));
                    }
                    details.add(rowData);
                }
                dataForm.put(compId_cur, details);
            } else {
                // 主表数据处理
                dataForm.put(compId_src, YDConf.getDataByCompId(formData, compId_cur));
            }
        }
        // 发起流程/创建表单
        YDConf.FORM_OPERATION type = data.containsKey("processCode") ? YDConf.FORM_OPERATION.start : YDConf.FORM_OPERATION.create;
        return ydClient.operateData(YDParam.builder()
                .formUuid(UtilMap.getString(data, "formUuid"))
                .processCode(UtilMap.getString(data, "processCode"))
                .formDataJson(JSON.toJSONString(dataForm))
                .build(), type);
    }

    /**
     * 全表复制 [两张表组件完全一致]
     */
    @Override
    public Object mirrorFormData(String instanceId, String formUuid, String processCode, Map updateData, String updateInstanceId) {

        YDConf.FORM_OPERATION type = StringUtils.isNotBlank(processCode) ? YDConf.FORM_OPERATION.start : YDConf.FORM_OPERATION.create;
        Map<String, ?> formData = ydClient.queryData(YDParam.builder()
                        .formInstanceId(instanceId)
                        .build(),
                YDConf.FORM_QUERY.retrieve_id).getFormData();

        Map dataForm = UtilMap.empty();
        for (String compId : formData.keySet()) {
            // ppExt: 组件会返回带有_id/_value字段, 关联表单 & 成员组件赋值为原字段 [关联表单仅仅会返回带Id字段, 成员组件不带Id返回姓名过滤]
            if (compId.endsWith("_value") || (compId.startsWith("employeeField_") && !compId.endsWith("_id"))) {
                continue;
            }
            if (compId.endsWith("_id")) {
                if (compId.startsWith("employeeField_") || compId.startsWith("associationFormField_")) {
                    compId = compId.replace("_id", "");
                } else {
                    continue;
                }
            }
            dataForm.put(compId, YDConf.getDataByCompId(formData, compId));
            if (compId.startsWith("tableField_")) {

                List<Map<String, ?>> details = (List<Map<String, ?>>) formData.get(compId);
                List<Map> table = new ArrayList<>();
                for (Map detail : details) {
                    Map row = UtilMap.empty();
                    for (String subId : details.get(0).keySet()) {
                        // ppExt: 组件会返回带有_id/_value字段, 关联表单 & 成员组件赋值为原字段 [关联表单仅仅会返回带Id字段, 成员组件不带Id返回姓名过滤]
                        if (subId.endsWith("_value") || (subId.startsWith("employeeField_") && !subId.endsWith("_id"))) {
                            continue;
                        }
                        if (subId.endsWith("_id")) {
                            if (subId.startsWith("employeeField_") || subId.startsWith("associationFormField_")) {
                                subId = subId.replace("_id", "");
                            } else {
                                continue;
                            }
                        }
                        row.put(subId, YDConf.getDataByCompId(detail, subId));
                    }
                    table.add(row);
                }
                dataForm.put(compId, table);
            }
        }
        UtilMap.putAll(dataForm, updateData);
        if (UtilString.isBlankCompatNull(updateInstanceId)) {
            return ydClient.operateData(YDParam.builder()
                    .formUuid(formUuid)
                    .processCode(processCode)
                    .userId(String.valueOf(UtilMap.getList(formData, "employeeField_l843wfsm_id").get(0)))
                    .formDataJson(JSON.toJSONString(dataForm))
                    .build(), type);
        }
        return ydClient.operateData(YDParam.builder()
                .formInstanceId(updateInstanceId)
                .updateFormDataJson(JSON.toJSONString(dataForm))
                .build(), YDConf.FORM_OPERATION.update);
    }

    /**
     * upsert方法
     */
    @Override
    public Object upsertFormData(String formUuid, Map condition, Map formData, UpsertLambda lambda) {
        YDParam ydParam = YDParam.builder()
                .formUuid(formUuid)
                .searchFieldJson(JSON.toJSONString(condition))
                .build();
        // 查询数据, 是否存在
        List<Map> dataList = (List<Map>) ydClient.queryData(ydParam, YDConf.FORM_QUERY.retrieve_search_form).getData();
        McException.assertAccessException(dataList.size() > 1, "upsert方法, 查询条件返回数据不唯一");
        // 异步回调, 查询结果
        if (ObjectUtil.isNotNull(lambda)) {
            Map form = lambda.dataList(dataList);
            // 若返回为空, 不执行
            if (ObjectUtil.isNull(form)) {
                return null;
            }
            // 回调数据, 写入表单
            formData.putAll(form);
        }
        if (dataList.size() > 0) {
            ydParam.setUpdateFormDataJson(JSON.toJSONString(formData));
            ydParam.setFormInstanceId(dataList.get(0).get("formInstanceId").toString());
            return ydClient.operateData(ydParam, YDConf.FORM_OPERATION.update);
        }
        formData.putAll(condition); // 新增写入查询条件数据
        ydParam.setFormDataJson(JSON.toJSONString(formData));
        return ydClient.operateData(ydParam, YDConf.FORM_OPERATION.create);
    }
}
