package com.malk.benteler.service;

import com.malk.benteler.dto.EiamBatchItemResult;
import com.malk.benteler.dto.EiamBatchOperation;
import com.malk.benteler.dto.EiamBatchResult;
import com.malk.benteler.dto.EiamBatchStage;
import com.malk.benteler.dto.EiamCreateUserItem;
import com.malk.benteler.dto.EiamDeleteUserItem;
import com.malk.benteler.dto.EiamUpdateUserItem;
import com.malk.server.common.McException;
import com.malk.server.eiam.EiamApiResponse;
import com.malk.server.eiam.EiamConf;
import com.malk.server.eiam.EiamCustomField;
import com.malk.server.eiam.EiamCustomFieldUpdate;
import com.malk.service.eiam.EiamClient_User;
import com.malk.service.eiam.EiamService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

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

/**
 * 本特勒 EIAM 批量业务编排。
 */
@Service
public class EiamLocalService {

    private final EiamService eiamService;
    private final EiamClient_User eiamClientUser;
    private final EiamConf eiamConf;

    public EiamLocalService(EiamService eiamService, EiamClient_User eiamClientUser,
                            EiamConf eiamConf) {
        this.eiamService = eiamService;
        this.eiamClientUser = eiamClientUser;
        this.eiamConf = eiamConf;
    }

    /**
     * 批量创建用户，单条失败不中断后续条目。
     *
     * @param items 创建条目
     * @return 批量结果
     */
    public EiamBatchResult batchCreate(List<EiamCreateUserItem> items) {
        validateBatch(items);
        String token = eiamService.getAccessToken();
        List<EiamBatchItemResult> results = new ArrayList<>();
        for (int index = 0; index < items.size(); index++) {
            results.add(createOne(token, items.get(index), index));
        }
        return EiamBatchResult.of(EiamBatchOperation.CREATE, results);
    }

    /**
     * 批量更新用户，支持账户属性和主组织变更。
     *
     * @param items 更新条目
     * @return 批量结果
     */
    public EiamBatchResult batchUpdate(List<EiamUpdateUserItem> items) {
        validateBatch(items);
        String token = eiamService.getAccessToken();
        List<EiamBatchItemResult> results = new ArrayList<>();
        for (int index = 0; index < items.size(); index++) {
            results.add(updateOne(token, items.get(index), index));
        }
        return EiamBatchResult.of(EiamBatchOperation.UPDATE, results);
    }

    /**
     * 批量删除用户，单条失败不中断后续条目。
     *
     * @param items 删除条目
     * @return 批量结果
     */
    public EiamBatchResult batchDelete(List<EiamDeleteUserItem> items) {
        validateBatch(items);
        String token = eiamService.getAccessToken();
        List<EiamBatchItemResult> results = new ArrayList<>();
        for (int index = 0; index < items.size(); index++) {
            results.add(deleteOne(token, items.get(index), index));
        }
        return EiamBatchResult.of(EiamBatchOperation.DELETE, results);
    }

    private EiamBatchItemResult createOne(String token, EiamCreateUserItem item, int index) {
        EiamBatchStage stage = EiamBatchStage.VALIDATE;
        try {
            validateCreateItem(item);
            stage = EiamBatchStage.CREATE_USER;
            EiamApiResponse response = eiamClientUser.createUser(token, eiamConf.getInstanceId(),
                    eiamConf.getApplicationId(), item.getUsername(),
                    item.getPrimaryOrganizationalUnitId(), createBody(item));
            assertEiamSuccess(response);
            if (StringUtils.isBlank(response.getUserId())) {
                throw new McException("EIAM_EMPTY_USER_ID", "CreateUser 成功响应缺少 userId");
            }
            return success(index, item.getFormInstanceId(), item.getUsername(), response.getUserId());
        } catch (RuntimeException ex) {
            return failure(index, item == null ? null : item.getFormInstanceId(),
                    item == null ? null : item.getUsername(), null, stage, ex, false);
        }
    }

    private EiamBatchItemResult updateOne(String token, EiamUpdateUserItem item, int index) {
        EiamBatchStage stage = EiamBatchStage.VALIDATE;
        boolean updateCompleted = false;
        try {
            validateUpdateItem(item);
            Map<String, Object> patchBody = updateBody(item);
            if (!patchBody.isEmpty()) {
                stage = EiamBatchStage.PATCH_USER;
                assertEiamSuccess(eiamClientUser.patchUser(token, eiamConf.getInstanceId(),
                        eiamConf.getApplicationId(), item.getUserId(), patchBody));
                updateCompleted = true;
            }
            if (StringUtils.isNotBlank(item.getPrimaryOrganizationalUnitId())) {
                stage = EiamBatchStage.SET_PRIMARY_ORG;
                assertEiamSuccess(eiamClientUser.setUserPrimaryOrganizationalUnit(token,
                        eiamConf.getInstanceId(), eiamConf.getApplicationId(), item.getUserId(),
                        item.getPrimaryOrganizationalUnitId()));
                updateCompleted = true;
            }
            if (StringUtils.isNotBlank(item.getAdditionalOrganizationalUnitId())) {
                stage = EiamBatchStage.ADD_ORG;
                assertEiamSuccess(eiamClientUser.addUserToOrganizationalUnits(token,
                        eiamConf.getInstanceId(), eiamConf.getApplicationId(), item.getUserId(),
                        Collections.singletonList(item.getAdditionalOrganizationalUnitId())));
            }
            return success(index, item.getFormInstanceId(), userKey(item), item.getUserId());
        } catch (RuntimeException ex) {
            return failure(index, item == null ? null : item.getFormInstanceId(),
                    item == null ? null : userKey(item), item == null ? null : item.getUserId(),
                    stage, ex, updateCompleted);
        }
    }

    private EiamBatchItemResult deleteOne(String token, EiamDeleteUserItem item, int index) {
        EiamBatchStage stage = EiamBatchStage.VALIDATE;
        try {
            validateFormInstanceId(item == null ? null : item.getFormInstanceId());
            if (item == null || StringUtils.isBlank(item.getUserId())) {
                throw new McException("EIAM_ITEM_INVALID", "userId 不能为空");
            }
            stage = EiamBatchStage.DELETE_USER;
            assertEiamSuccess(eiamClientUser.deleteUser(token, eiamConf.getInstanceId(),
                    eiamConf.getApplicationId(), item.getUserId()));
            return success(index, item.getFormInstanceId(), deleteUserKey(item), item.getUserId());
        } catch (RuntimeException ex) {
            return failure(index, item == null ? null : item.getFormInstanceId(),
                    item == null ? null : deleteUserKey(item), item == null ? null : item.getUserId(),
                    stage, ex, false);
        }
    }

    private Map<String, Object> createBody(EiamCreateUserItem item) {
        Map<String, Object> body = new HashMap<>();
        putIfNotBlank(body, "displayName", item.getDisplayName());
        String phoneNumber = StringUtils.defaultIfBlank(item.getPhoneNumber(), item.getUsername());
        putIfNotBlank(body, "phoneNumber", phoneNumber);
        if (StringUtils.isNotBlank(phoneNumber)) {
            body.put("phoneRegion", StringUtils.defaultIfBlank(item.getPhoneRegion(), "86"));
            body.put("phoneNumberVerified", true);
        }
        putIfNotBlank(body, "email", item.getEmail());
        if (StringUtils.isNotBlank(item.getEmail())) {
            body.put("emailVerified", false);
        }
        putIfNotBlank(body, "description", item.getDescription());
        if (item.getCustomFields() != null) {
            body.put("customFields", item.getCustomFields());
        }
        Map<String, Object> passwordConfig = new HashMap<>();
        passwordConfig.put("passwordInitializationPolicyPriority", "custom");
        passwordConfig.put("passwordForcedUpdateStatus", "enabled");
        // prd 客户不接收初始密码通知，用户首次登录时通过重置密码流程完成密码设置。
        passwordConfig.put("passwordInitializationType", "random");
        body.put("passwordInitializationConfig", passwordConfig);
        return body;
    }

    private Map<String, Object> updateBody(EiamUpdateUserItem item) {
        Map<String, Object> body = new HashMap<>();
        putIfNotBlank(body, "username", item.getUsername());
        putIfNotBlank(body, "displayName", item.getDisplayName());
        putIfNotBlank(body, "phoneNumber", item.getPhoneNumber());
        if (StringUtils.isNotBlank(item.getPhoneNumber())) {
            body.put("phoneRegion", StringUtils.defaultIfBlank(item.getPhoneRegion(), "86"));
            body.put("phoneNumberVerified", true);
        }
        putIfNotBlank(body, "email", item.getEmail());
        if (StringUtils.isNotBlank(item.getEmail())) {
            body.put("emailVerified", false);
        }
        if (item.getCustomFields() != null && !item.getCustomFields().isEmpty()) {
            body.put("customFields", item.getCustomFields());
        }
        return body;
    }

    private void validateCreateItem(EiamCreateUserItem item) {
        validateFormInstanceId(item == null ? null : item.getFormInstanceId());
        if (item == null || StringUtils.isBlank(item.getUsername())) {
            throw new McException("EIAM_ITEM_INVALID", "username 不能为空");
        }
        if (StringUtils.isBlank(item.getDisplayName())) {
            throw new McException("EIAM_ITEM_INVALID", "displayName 不能为空");
        }
        if (StringUtils.isBlank(item.getPrimaryOrganizationalUnitId())) {
            throw new McException("EIAM_ITEM_INVALID", "primaryOrganizationalUnitId 不能为空");
        }
        // prd 新增账号必须完整携带宜搭主表和人员子表中的 EIAM 自定义字段。
        validateRequiredCustomField(item, "department", "iDaaS 部门名称");
        validateRequiredCustomField(item, "company_name", "所属公司");
        validateRequiredCustomField(item, "company_code", "公司代码");
        validateRequiredCustomField(item, "job_title", "职位");
    }

    private void validateRequiredCustomField(EiamCreateUserItem item, String fieldName,
                                             String displayName) {
        if (item.getCustomFields() != null) {
            for (EiamCustomField field : item.getCustomFields()) {
                if (field != null && StringUtils.equals(fieldName, field.getFieldName())
                        && StringUtils.isNotBlank(field.getFieldValue())) {
                    return;
                }
            }
        }
        throw new McException("EIAM_ITEM_INVALID", displayName + " 不能为空");
    }

    private void validateUpdateItem(EiamUpdateUserItem item) {
        validateFormInstanceId(item == null ? null : item.getFormInstanceId());
        if (item == null || StringUtils.isBlank(item.getUserId())) {
            throw new McException("EIAM_ITEM_INVALID", "userId 不能为空");
        }
        if (containsUpdateContent(item, BentelerYidaFormMapper.UPDATE_PHONE)
                && StringUtils.isBlank(item.getPhoneNumber())) {
            throw new McException("EIAM_ITEM_INVALID", "手机号不能为空");
        }
        if (containsUpdateContent(item, BentelerYidaFormMapper.UPDATE_EMPLOYEE_NUMBER)) {
            validateCustomFieldUpdate(item, "employee_id_number", "工号");
        }
        if (containsUpdateContent(item, BentelerYidaFormMapper.UPDATE_JOB_TITLE)) {
            validateCustomFieldUpdate(item, "job_title", "职位");
        }
        if (updateBody(item).isEmpty() && StringUtils.isBlank(item.getPrimaryOrganizationalUnitId())
                && StringUtils.isBlank(item.getAdditionalOrganizationalUnitId())) {
            throw new McException("EIAM_ITEM_INVALID", "更新内容不能为空");
        }
    }

    private boolean containsUpdateContent(EiamUpdateUserItem item, String updateContent) {
        return item.getUpdateContents() != null && item.getUpdateContents().contains(updateContent);
    }

    private void validateCustomFieldUpdate(EiamUpdateUserItem item, String fieldName,
                                           String displayName) {
        if (item.getCustomFields() != null) {
            for (EiamCustomFieldUpdate field : item.getCustomFields()) {
                if (field != null && StringUtils.equals(fieldName, field.getFieldName())
                        && StringUtils.isNotBlank(field.getFieldValue())) {
                    return;
                }
            }
        }
        throw new McException("EIAM_ITEM_INVALID", displayName + " 不能为空");
    }

    private void validateBatch(List<?> items) {
        if (items == null || items.isEmpty()) {
            throw new McException("EIAM_BATCH_EMPTY", "items 不能为空");
        }
    }

    private void validateFormInstanceId(String formInstanceId) {
        if (StringUtils.isBlank(formInstanceId)) {
            throw new McException("EIAM_ITEM_INVALID", "formInstanceId 不能为空");
        }
    }

    private void assertEiamSuccess(EiamApiResponse response) {
        if (response == null) {
            throw new McException("EIAM_EMPTY_RESPONSE", "EIAM 响应为空");
        }
        String code = StringUtils.defaultIfBlank(response.getCode(), response.getError());
        if (StringUtils.isBlank(code)) {
            return;
        }
        String message = StringUtils.defaultIfBlank(response.getMessage(), response.getErrorDescription());
        throw new McException(code, StringUtils.defaultIfBlank(message, "EIAM 调用失败"));
    }

    private EiamBatchItemResult success(int index, String formInstanceId, String userKey,
                                        String userId) {
        return EiamBatchItemResult.builder().index(index).formInstanceId(formInstanceId)
                .userKey(userKey).userId(userId).success(true).stage(EiamBatchStage.COMPLETED)
                .code("SUCCESS").message("执行成功").build();
    }

    private EiamBatchItemResult failure(int index, String formInstanceId, String userKey,
                                        String userId, EiamBatchStage stage, RuntimeException ex,
                                        boolean partialUpdate) {
        String code = ex instanceof McException ? ((McException) ex).getCode() : "EIAM_CALL_ERROR";
        String message = StringUtils.defaultIfBlank(ex.getMessage(), "EIAM 调用失败");
        if (partialUpdate) {
            message = "账户属性可能已更新；" + message;
        }
        return EiamBatchItemResult.builder().index(index).formInstanceId(formInstanceId)
                .userKey(userKey).userId(userId).success(false).stage(stage)
                .code(code).message(message).build();
    }

    private void putIfNotBlank(Map<String, Object> target, String key, String value) {
        if (StringUtils.isNotBlank(value)) {
            target.put(key, value);
        }
    }

    private String userKey(EiamUpdateUserItem item) {
        return StringUtils.defaultIfBlank(item.getUsername(), item.getUserId());
    }

    private String deleteUserKey(EiamDeleteUserItem item) {
        return StringUtils.defaultIfBlank(item.getUsername(), item.getUserId());
    }
}
