package com.malk.benteler.service;

import com.malk.benteler.config.BentelerYidaConf;
import com.malk.benteler.dto.EiamBatchItemResult;
import com.malk.benteler.dto.EiamCreateUserItem;
import com.malk.benteler.dto.EiamDeleteUserItem;
import com.malk.benteler.dto.EiamUpdateUserItem;
import com.malk.server.eiam.EiamCustomField;
import com.malk.server.eiam.EiamCustomFieldUpdate;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 宜搭真实 fieldId 与 EIAM DTO 的纯映射器。
 */
@Component
public class BentelerYidaFormMapper {

    private static final String STATUS_SUCCESS = "成功";
    private static final String STATUS_FAILED = "失败";
    static final String REPLACE_PRIMARY_ORG = "替换部门";
    static final String ADD_ORG = "增加部门";
    static final String UPDATE_PHONE = "手机号";
    static final String UPDATE_EMPLOYEE_NUMBER = "工号";
    static final String UPDATE_JOB_TITLE = "职位";

    private final BentelerYidaConf conf;

    public BentelerYidaFormMapper(BentelerYidaConf conf) {
        this.conf = conf;
    }

    /**
     * 映射入职人员明细。
     *
     * @param formInstanceId 宜搭实例 ID
     * @param formData 主表数据
     * @param rows 人员子表全量数据
     * @return EIAM 创建条目
     */
    public List<EiamCreateUserItem> mapCreateItems(String formInstanceId,
                                                   Map<String, Object> formData,
                                                   List<Map<String, Object>> rows) {
        List<EiamCreateUserItem> items = new ArrayList<>();
        String organizationalUnitId = stringValue(formData.get(
                conf.getOnboardingOrganizationalUnitIdFieldId()));
        for (Map<String, Object> row : rows) {
            EiamCreateUserItem item = new EiamCreateUserItem();
            item.setFormInstanceId(formInstanceId);
            item.setUsername(stringValue(row.get(conf.getOnboardingPhoneFieldId())));
            item.setDisplayName(stringValue(row.get(conf.getOnboardingNameFieldId())));
            item.setPhoneNumber(item.getUsername());
            item.setEmail(stringValue(row.get(conf.getOnboardingEmailFieldId())));
            item.setDescription(stringValue(row.get(conf.getOnboardingDescriptionFieldId())));
            item.setPrimaryOrganizationalUnitId(organizationalUnitId);
            item.setCustomFields(createCustomFields(formData, row));
            items.add(item);
        }
        return items;
    }

    /**
     * 映射人员部门更新明细。
     *
     * @param formInstanceId 宜搭实例 ID
     * @param rows 人员子表全量数据
     * @param organizationalUnitId EIAM 目标部门 ID
     * @param updateContents 更新内容多选值
     * @return EIAM 更新条目
     */
    public List<EiamUpdateUserItem> mapUpdateItems(String formInstanceId,
                                                   List<Map<String, Object>> rows,
                                                   String organizationalUnitId,
                                                   List<String> updateContents) {
        List<EiamUpdateUserItem> items = new ArrayList<>();
        for (Map<String, Object> row : rows) {
            EiamUpdateUserItem item = new EiamUpdateUserItem();
            item.setFormInstanceId(formInstanceId);
            item.setUserId(firstString(row.get(conf.getUpdateEmployeeFieldId() + "_id")));
            item.setUpdateContents(updateContents);
            if (updateContents.contains(REPLACE_PRIMARY_ORG)) {
                item.setPrimaryOrganizationalUnitId(organizationalUnitId);
            }
            if (updateContents.contains(ADD_ORG)) {
                item.setAdditionalOrganizationalUnitId(organizationalUnitId);
            }
            mapUpdatePatchFields(item, row, updateContents);
            items.add(item);
        }
        return items;
    }

    /**
     * 映射离职人员明细。
     *
     * @param formInstanceId 宜搭实例 ID
     * @param rows 人员子表全量数据
     * @return EIAM 删除条目
     */
    public List<EiamDeleteUserItem> mapDeleteItems(String formInstanceId,
                                                   List<Map<String, Object>> rows) {
        List<EiamDeleteUserItem> items = new ArrayList<>();
        for (Map<String, Object> row : rows) {
            EiamDeleteUserItem item = new EiamDeleteUserItem();
            item.setFormInstanceId(formInstanceId);
            item.setUserId(firstString(row.get(conf.getOffboardingEmployeeFieldId() + "_id")));
            items.add(item);
        }
        return items;
    }

    /**
     * 按表单类型全量重建子表，成员字段只写 userId 数组。
     *
     * @param tableFieldId 子表 fieldId
     * @param rows 原始全量行
     * @param results EIAM 逐行执行结果
     * @return 可用于宜搭 updateForm 的全量行
     */
    public List<Map<String, Object>> rebuildRows(String tableFieldId,
                                                 List<Map<String, Object>> rows,
                                                 List<EiamBatchItemResult> results) {
        List<Map<String, Object>> rebuilt = new ArrayList<>();
        for (int index = 0; index < rows.size(); index++) {
            Map<String, Object> row = rows.get(index);
            Map<String, Object> target = new LinkedHashMap<>();
            if (StringUtils.equals(tableFieldId, conf.getOnboardingTableFieldId())) {
                copyFields(row, target, Arrays.asList(conf.getOnboardingNameFieldId(),
                        conf.getOnboardingPhoneFieldId(), conf.getOnboardingEmailFieldId(),
                        conf.getOnboardingDescriptionFieldId(), conf.getOnboardingEmployeeNumberFieldId(),
                        conf.getOnboardingJobTitleFieldId()));
                copyEmployee(row, target, conf.getOnboardingManagerFieldId());
            } else if (StringUtils.equals(tableFieldId, conf.getUpdateTableFieldId())) {
                copyFields(row, target, Arrays.asList(conf.getUpdatePhoneFieldId(),
                        conf.getUpdateEmployeeNumberFieldId(), conf.getUpdateJobTitleFieldId(),
                        conf.getUpdateDescriptionFieldId()));
                copyEmployee(row, target, conf.getUpdateEmployeeFieldId());
            } else if (StringUtils.equals(tableFieldId, conf.getOffboardingTableFieldId())) {
                copyFields(row, target, Arrays.asList(conf.getOffboardingRemarkFieldId()));
                copyEmployee(row, target, conf.getOffboardingEmployeeFieldId());
            }
            target.put(conf.getDetailStatusFieldId(), results.get(index).isSuccess()
                    ? STATUS_SUCCESS : STATUS_FAILED);
            rebuilt.add(target);
        }
        return rebuilt;
    }

    /**
     * 聚合失败人员及原因，用于宜搭主表失败说明字段。
     *
     * @param tableFieldId 子表 fieldId
     * @param rows 原始全量行
     * @param results EIAM 逐行执行结果
     * @return 每条失败占一行；全部成功时返回空字符串
     */
    public String buildFailureMessage(String tableFieldId,
                                      List<Map<String, Object>> rows,
                                      List<EiamBatchItemResult> results) {
        List<String> messages = new ArrayList<>();
        for (int index = 0; index < results.size(); index++) {
            EiamBatchItemResult result = results.get(index);
            if (result.isSuccess()) {
                continue;
            }
            Map<String, Object> row = index < rows.size() ? rows.get(index) : null;
            String personName = personName(tableFieldId, row);
            if (StringUtils.isBlank(personName)) {
                personName = "第" + (index + 1) + "行";
            }
            String reason = StringUtils.defaultIfBlank(result.getMessage(), result.getCode());
            messages.add(personName + " - " + StringUtils.defaultIfBlank(reason, "执行失败"));
        }
        return String.join("\n", messages);
    }

    private List<EiamCustomField> createCustomFields(Map<String, Object> formData,
                                                     Map<String, Object> row) {
        List<EiamCustomField> fields = new ArrayList<>();
        addCustomField(fields, "company_name", formData.get(conf.getOnboardingCompanyFieldId()));
        addCustomField(fields, "company_code", formData.get(conf.getOnboardingCompanyCodeFieldId()));
        addCustomField(fields, "employee_id_number", row.get(conf.getOnboardingEmployeeNumberFieldId()));
        addCustomField(fields, "job_title", row.get(conf.getOnboardingJobTitleFieldId()));
        addCustomField(fields, "department", formData.get(conf.getOnboardingDepartmentFieldId()));
        addCustomField(fields, "direct_line_manager",
                firstString(row.get(conf.getOnboardingManagerFieldId() + "_id")));
        return fields.isEmpty() ? null : fields;
    }

    private void mapUpdatePatchFields(EiamUpdateUserItem item, Map<String, Object> row,
                                      List<String> updateContents) {
        if (updateContents.contains(UPDATE_PHONE)) {
            String phoneNumber = stringValue(row.get(conf.getUpdatePhoneFieldId()));
            item.setUsername(phoneNumber);
            item.setPhoneNumber(phoneNumber);
            item.setPhoneRegion("86");
        }
        List<EiamCustomFieldUpdate> customFields = new ArrayList<>();
        if (updateContents.contains(UPDATE_EMPLOYEE_NUMBER)) {
            addCustomFieldUpdate(customFields, "employee_id_number",
                    row.get(conf.getUpdateEmployeeNumberFieldId()));
        }
        if (updateContents.contains(UPDATE_JOB_TITLE)) {
            addCustomFieldUpdate(customFields, "job_title",
                    row.get(conf.getUpdateJobTitleFieldId()));
        }
        item.setCustomFields(customFields.isEmpty() ? null : customFields);
    }

    private void addCustomFieldUpdate(List<EiamCustomFieldUpdate> fields, String fieldName,
                                      Object value) {
        String fieldValue = stringValue(value);
        if (StringUtils.isBlank(fieldValue)) {
            return;
        }
        EiamCustomFieldUpdate field = new EiamCustomFieldUpdate();
        field.setFieldName(fieldName);
        field.setFieldValue(fieldValue);
        field.setOperation("replace");
        fields.add(field);
    }

    private void addCustomField(List<EiamCustomField> fields, String fieldName, Object value) {
        String fieldValue = stringValue(value);
        if (StringUtils.isBlank(fieldValue)) {
            return;
        }
        EiamCustomField field = new EiamCustomField();
        field.setFieldName(fieldName);
        field.setFieldValue(fieldValue);
        fields.add(field);
    }

    private void copyFields(Map<String, Object> source, Map<String, Object> target,
                            List<String> fieldIds) {
        for (String fieldId : fieldIds) {
            if (StringUtils.isNotBlank(fieldId) && source.get(fieldId) != null) {
                target.put(fieldId, source.get(fieldId));
            }
        }
    }

    private void copyEmployee(Map<String, Object> source, Map<String, Object> target,
                              String fieldId) {
        if (StringUtils.isBlank(fieldId)) {
            return;
        }
        List<String> userIds = stringList(source.get(fieldId + "_id"));
        if (!userIds.isEmpty()) {
            target.put(fieldId, userIds);
        }
    }

    private String personName(String tableFieldId, Map<String, Object> row) {
        if (row == null) {
            return null;
        }
        if (StringUtils.equals(tableFieldId, conf.getOnboardingTableFieldId())) {
            return displayText(row.get(conf.getOnboardingNameFieldId()));
        }
        if (StringUtils.equals(tableFieldId, conf.getUpdateTableFieldId())) {
            return displayText(row.get(conf.getUpdateEmployeeFieldId()));
        }
        if (StringUtils.equals(tableFieldId, conf.getOffboardingTableFieldId())) {
            return displayText(row.get(conf.getOffboardingEmployeeFieldId()));
        }
        return null;
    }

    private String displayText(Object value) {
        if (value instanceof Iterable) {
            for (Object item : (Iterable<?>) value) {
                String text = displayText(item);
                if (StringUtils.isNotBlank(text)) {
                    return text;
                }
            }
            return null;
        }
        if (value instanceof Map) {
            Map<?, ?> map = (Map<?, ?>) value;
            for (String key : Arrays.asList("name", "displayName", "label")) {
                String text = displayText(map.get(key));
                if (StringUtils.isNotBlank(text)) {
                    return text;
                }
            }
            return null;
        }
        return stringValue(value);
    }

    private String firstString(Object value) {
        List<String> values = stringList(value);
        return values.isEmpty() ? null : values.get(0);
    }

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

    private String stringValue(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof BigDecimal) {
            return ((BigDecimal) value).toPlainString();
        }
        if (value instanceof Number) {
            return new BigDecimal(value.toString()).toPlainString();
        }
        return StringUtils.trimToNull(String.valueOf(value));
    }
}
