package com.malk.benteler.service;

import com.alibaba.fastjson.JSON;
import com.malk.benteler.config.BentelerYidaConf;
import com.malk.benteler.dto.EiamBatchOperation;
import com.malk.benteler.dto.EiamBatchResult;
import com.malk.benteler.dto.EiamFormSyncResult;
import com.malk.server.aliwork.YDAuth;
import com.malk.server.aliwork.YDConf;
import com.malk.server.aliwork.YDParam;
import com.malk.server.common.McException;
import com.malk.service.aliwork.YDClient_Form;
import com.malk.service.aliwork.YDService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

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

/**
 * 基于一个宜搭实例 ID 完成查询、批量 EIAM 执行和全量回写。
 */
@Slf4j
@Service
public class BentelerYidaSyncService {

    private final YDClient_Form ydClientForm;
    private final YDService ydService;
    private final YDConf ydConf;
    private final BentelerYidaConf conf;
    private final BentelerYidaFormMapper mapper;
    private final EiamLocalService eiamLocalService;

    public BentelerYidaSyncService(YDClient_Form ydClientForm, YDService ydService,
                                   YDConf ydConf, BentelerYidaConf conf,
                                   BentelerYidaFormMapper mapper,
                                   EiamLocalService eiamLocalService) {
        this.ydClientForm = ydClientForm;
        this.ydService = ydService;
        this.ydConf = ydConf;
        this.conf = conf;
        this.mapper = mapper;
        this.eiamLocalService = eiamLocalService;
    }

    /**
     * 查询入职实例并批量创建 EIAM 用户。
     *
     * @param formInstanceId 宜搭实例 ID
     * @return 执行及回写结果
     */
    public EiamFormSyncResult syncCreate(String formInstanceId) {
        return sync(formInstanceId, EiamBatchOperation.CREATE,
                conf.getOnboardingFormUuid(), conf.getOnboardingTableFieldId());
    }

    /**
     * 查询人员部门更新实例并批量更新 EIAM 用户。
     *
     * @param formInstanceId 宜搭实例 ID
     * @return 执行及回写结果
     */
    public EiamFormSyncResult syncUpdate(String formInstanceId) {
        return sync(formInstanceId, EiamBatchOperation.UPDATE,
                conf.getUpdateFormUuid(), conf.getUpdateTableFieldId());
    }

    /**
     * 查询离职实例并批量删除 EIAM 用户。
     *
     * @param formInstanceId 宜搭实例 ID
     * @return 执行及回写结果
     */
    public EiamFormSyncResult syncDelete(String formInstanceId) {
        return sync(formInstanceId, EiamBatchOperation.DELETE,
                conf.getOffboardingFormUuid(), conf.getOffboardingTableFieldId());
    }

    private EiamFormSyncResult sync(String formInstanceId, EiamBatchOperation operation,
                                    String expectedFormUuid, String tableFieldId) {
        validateRequest(formInstanceId, tableFieldId);
        Map<String, Object> instance = ydClientForm.getForm(auth(), formInstanceId, null);
        validateForm(instance, expectedFormUuid);
        Map<String, Object> formData = formData(instance);
        List<Map<String, Object>> rows = resolveDetailRows(formInstanceId, tableFieldId,
                formData.get(tableFieldId));
        if (rows.isEmpty()) {
            throw new McException("YIDA_FORM_EMPTY", "宜搭人员子表不能为空");
        }
        EiamBatchResult batchResult = execute(operation, formInstanceId, formData, rows);
        return writeback(formInstanceId, tableFieldId, rows, batchResult);
    }

    private EiamBatchResult execute(EiamBatchOperation operation, String formInstanceId,
                                    Map<String, Object> formData,
                                    List<Map<String, Object>> rows) {
        if (operation == EiamBatchOperation.CREATE) {
            String organizationalUnitId = text(formData.get(
                    conf.getOnboardingOrganizationalUnitIdFieldId()));
            if (!StringUtils.startsWith(organizationalUnitId, "ou_")) {
                throw new McException("EIAM_ORG_INVALID", "iDaaS 部门 ID 无效");
            }
            return eiamLocalService.batchCreate(mapper.mapCreateItems(
                    formInstanceId, formData, rows));
        }
        if (operation == EiamBatchOperation.UPDATE) {
            List<String> updateContents = texts(formData.get(conf.getUpdateContentFieldId()));
            if (updateContents.isEmpty()) {
                throw new McException("EIAM_UPDATE_CONTENT_EMPTY", "更新内容不能为空");
            }
            validateUpdateContents(updateContents);
            String organizationalUnitId = null;
            if (requiresOrganizationalUnit(updateContents)) {
                organizationalUnitId = firstText(formData.get(
                        conf.getUpdateOrganizationalUnitIdFieldId()));
                if (!StringUtils.startsWith(organizationalUnitId, "ou_")) {
                    throw new McException("EIAM_ORG_INVALID", "iDaaS 部门 ID 无效");
                }
            }
            return eiamLocalService.batchUpdate(mapper.mapUpdateItems(
                    formInstanceId, rows, organizationalUnitId, updateContents));
        }
        return eiamLocalService.batchDelete(mapper.mapDeleteItems(formInstanceId, rows));
    }

    private EiamFormSyncResult writeback(String formInstanceId, String tableFieldId,
                                         List<Map<String, Object>> rows,
                                         EiamBatchResult batchResult) {
        Map<String, Object> update = new HashMap<>();
        update.put(tableFieldId, mapper.rebuildRows(tableFieldId, rows,
                batchResult.getItems()));
        update.put(conf.getFailureMessageFieldId(), mapper.buildFailureMessage(
                tableFieldId, rows, batchResult.getItems()));
        update.put(conf.getTotalFieldId(), batchResult.getTotal());
        update.put(conf.getSuccessFieldId(), batchResult.getSuccessCount());
        update.put(conf.getFailedFieldId(), batchResult.getFailedCount());
        Map<String, Object> bodyExt = new HashMap<>();
        bodyExt.put("useLatestVersion", true);
        bodyExt.put("ignoreEmpty", false);
        try {
            ydClientForm.updateForm(auth(), formInstanceId, JSON.toJSONString(update), bodyExt);
            return EiamFormSyncResult.of(formInstanceId, batchResult, true, "回写成功");
        } catch (RuntimeException ex) {
            log.error("宜搭实例执行结果回写失败, formInstanceId={}", formInstanceId, ex);
            return EiamFormSyncResult.of(formInstanceId, batchResult, false,
                    StringUtils.defaultIfBlank(ex.getMessage(), "宜搭回写失败"));
        }
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> formData(Map<String, Object> instance) {
        if (instance == null || instance.get("formData") == null) {
            throw new McException("YIDA_FORM_DATA_EMPTY", "宜搭实例数据为空");
        }
        Object value = instance.get("formData");
        if (value instanceof Map) {
            return (Map<String, Object>) value;
        }
        Map<String, Object> parsed = JSON.parseObject(String.valueOf(value), Map.class);
        if (parsed == null) {
            throw new McException("YIDA_FORM_DATA_INVALID", "宜搭实例 formData 格式错误");
        }
        return parsed;
    }

    @SuppressWarnings("unchecked")
    private List<Map<String, Object>> resolveDetailRows(String formInstanceId,
                                                        String tableFieldId,
                                                        Object inlineValue) {
        List<Map<String, Object>> inlineRows = inlineValue instanceof List
                ? (List<Map<String, Object>>) inlineValue : new ArrayList<>();
        // fixme 详情接口最多内联 50 行；只有恰好 50 行时才可能被截断，必须单独分页查询子表。
        if (inlineRows.size() == YDConf.PAGE_SIZE_DETAILS) {
            try {
                List<Map> details = ydService.queryDetails(YDParam.builder()
                        .appType(ydConf.getAppType())
                        .systemToken(ydConf.getSystemToken())
                        .formInstanceId(formInstanceId)
                        .tableFieldId(tableFieldId)
                        .pageNumber(1)
                        .build());
                return details == null ? inlineRows : (List<Map<String, Object>>) (List<?>) details;
            } catch (NullPointerException ex) {
                log.warn("宜搭子表分页查询空数据，退回内联 50 行, formInstanceId={}, tableFieldId={}",
                        formInstanceId, tableFieldId);
            }
        }
        return inlineRows;
    }

    private void validateRequest(String formInstanceId, String tableFieldId) {
        if (StringUtils.isBlank(formInstanceId)) {
            throw new McException("YIDA_FORM_INSTANCE_ID_EMPTY", "formInstanceId 不能为空");
        }
        if (StringUtils.isBlank(tableFieldId)) {
            throw new McException("YIDA_FIELD_CONFIG_EMPTY", "人员子表 fieldId 未配置");
        }
    }

    private void validateForm(Map<String, Object> instance, String expectedFormUuid) {
        if (instance == null) {
            throw new McException("YIDA_FORM_EMPTY", "宜搭实例查询结果为空");
        }
        String actualFormUuid = text(instance.get("modelUuid"));
        if (StringUtils.isNotBlank(expectedFormUuid) && StringUtils.isNotBlank(actualFormUuid)
                && !StringUtils.equals(expectedFormUuid, actualFormUuid)) {
            throw new McException("YIDA_FORM_MISMATCH", "宜搭实例与当前同步场景不匹配");
        }
    }

    private YDAuth auth() {
        return YDAuth.ofGlobal(ydConf);
    }

    private String firstText(Object value) {
        if (value instanceof Iterable) {
            for (Object item : (Iterable<?>) value) {
                return text(item);
            }
            return null;
        }
        return text(value);
    }

    private boolean requiresOrganizationalUnit(List<String> updateContents) {
        return updateContents.contains(BentelerYidaFormMapper.REPLACE_PRIMARY_ORG)
                || updateContents.contains(BentelerYidaFormMapper.ADD_ORG);
    }

    private void validateUpdateContents(List<String> updateContents) {
        // prd 替换部门和增加部门会产生冲突，即使页面已过滤，后端仍需兜底。
        if (updateContents.contains(BentelerYidaFormMapper.REPLACE_PRIMARY_ORG)
                && updateContents.contains(BentelerYidaFormMapper.ADD_ORG)) {
            throw new McException("EIAM_UPDATE_CONTENT_CONFLICT",
                    "替换部门和增加部门不能同时选择");
        }
    }

    private List<String> texts(Object value) {
        List<String> values = new ArrayList<>();
        if (value instanceof Iterable) {
            for (Object item : (Iterable<?>) value) {
                String itemText = text(item);
                if (StringUtils.isNotBlank(itemText)) {
                    values.add(itemText);
                }
            }
            return values;
        }
        String itemText = text(value);
        if (StringUtils.isNotBlank(itemText)) {
            values.add(itemText);
        }
        return values;
    }

    private String text(Object value) {
        return value == null ? null : StringUtils.trimToNull(String.valueOf(value));
    }
}
