package com.huimv.employment.service.enterprise;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huimv.employment.common.exception.BizException;
import com.huimv.employment.common.exception.ErrorCode;
import com.huimv.employment.dao.entity.FeConversation;
import com.huimv.employment.dao.entity.FeEnterprise;
import com.huimv.employment.dao.mapper.FeEnterpriseMapper;
import com.huimv.employment.service.conversation.ConversationService;
import com.huimv.employment.service.enterprise.dto.McpEnterpriseProfileResponse;
import com.huimv.employment.service.enterprise.dto.McpEnterpriseProfileUpdateRequest;
import com.huimv.employment.service.enterprise.dto.McpEnterpriseProfileUpdateResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * MCP 企业画像接口（交互规则 v4）。
 * <p>通过 session_id 定位会话用户，再取该用户默认企业画像；Agent 无需传递 enterprise_id。
 * 企业尚未认证时，获取画像返回空结构（不报错），便于会话初始化与草稿补全。</p>
 */
@Service
public class McpEnterpriseProfileService {

    private static final Logger log = LoggerFactory.getLogger(McpEnterpriseProfileService.class);

    private static final String STATUS_SUCCESS = "success";
    private static final String PREF_PREFIX = "preferences.";

    /** 可写入 profile_json.preferences 的偏好键 */
    private static final Set<String> ALLOWED_PREFERENCE_KEYS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
            "settlement_cycle",
            "default_region",
            "default_settlement_mode",
            "default_work_type",
            "default_insurance_level"
    )));

    /** settlement_cycle 合法值 */
    private static final Set<String> ALLOWED_SETTLEMENT_CYCLES = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
            "daily", "weekly", "biweekly", "monthly"
    )));

    private final FeEnterpriseMapper feEnterpriseMapper;
    private final ConversationService conversationService;
    private final EnterpriseService enterpriseService;
    private final ObjectMapper objectMapper;

    public McpEnterpriseProfileService(FeEnterpriseMapper feEnterpriseMapper,
                                       ConversationService conversationService,
                                       EnterpriseService enterpriseService,
                                       ObjectMapper objectMapper) {
        this.feEnterpriseMapper = feEnterpriseMapper;
        this.conversationService = conversationService;
        this.enterpriseService = enterpriseService;
        this.objectMapper = objectMapper;
    }

    public McpEnterpriseProfileResponse getProfile(String sessionId) {
        FeConversation conversation = conversationService.requireBySessionId(sessionId);
        FeEnterprise enterprise = enterpriseService.findEnterpriseByUserId(conversation.getUserId());
        if (enterprise == null) {
            return emptyProfile();
        }
        return toResponse(enterprise);
    }

    @Transactional(rollbackFor = Exception.class)
    public McpEnterpriseProfileUpdateResponse updateProfile(String sessionId, McpEnterpriseProfileUpdateRequest request) {
        FeEnterprise enterprise = requireEnterpriseBySession(sessionId);
        Map<String, Object> profileRoot = parseProfileJson(enterprise.getProfileJson());
        Map<String, Object> preferences = extractPreferences(profileRoot);

        int updatedCount = 0;
        for (Map.Entry<String, Object> entry : request.getUpdates().entrySet()) {
            if (entry.getKey() == null) {
                continue;
            }
            String key = entry.getKey().trim();
            if (!StringUtils.hasText(key)) {
                continue;
            }
            Object value = entry.getValue();
            if (applyUpdate(enterprise, profileRoot, preferences, key, value)) {
                updatedCount++;
            }
        }

        if (updatedCount == 0) {
            throw new BizException(ErrorCode.BAD_REQUEST, "未识别任何可更新字段");
        }

        profileRoot.put("preferences", preferences);
        enterprise.setProfileJson(writeProfileJson(profileRoot));
        enterprise.setUpdateTime(LocalDateTime.now());
        feEnterpriseMapper.updateById(enterprise);

        McpEnterpriseProfileUpdateResponse response = new McpEnterpriseProfileUpdateResponse();
        response.setUpdatedFields(updatedCount);
        response.setStatus(STATUS_SUCCESS);
        return response;
    }

    private FeEnterprise requireEnterpriseBySession(String sessionId) {
        FeConversation conversation = conversationService.requireBySessionId(sessionId);
        FeEnterprise enterprise = enterpriseService.findEnterpriseByUserId(conversation.getUserId());
        if (enterprise == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "请先完成企业认证");
        }
        return enterprise;
    }

    private static McpEnterpriseProfileResponse emptyProfile() {
        McpEnterpriseProfileResponse response = new McpEnterpriseProfileResponse();
        response.setPreferences(new LinkedHashMap<>());
        return response;
    }

    private McpEnterpriseProfileResponse toResponse(FeEnterprise enterprise) {
        Map<String, Object> profileRoot = parseProfileJson(enterprise.getProfileJson());
        Map<String, Object> preferences = extractPreferences(profileRoot);

        McpEnterpriseProfileResponse response = new McpEnterpriseProfileResponse();
        response.setCompanyName(enterprise.getName());
        response.setCompanyAddress(enterprise.getRegisteredAddress());
        response.setIndustry(enterprise.getIndustry());
        response.setTaxQualification(readString(profileRoot.get("tax_qualification")));
        response.setPreferences(preferences);
        return response;
    }

    private boolean applyUpdate(FeEnterprise enterprise,
                                Map<String, Object> profileRoot,
                                Map<String, Object> preferences,
                                String key,
                                Object value) {
        switch (key) {
            case "company_name":
                enterprise.setName(requireNonBlankText(value, key));
                return true;
            case "company_address":
                enterprise.setRegisteredAddress(requireNonBlankText(value, key));
                return true;
            case "industry":
                enterprise.setIndustry(toNullableText(value));
                return true;
            case "scale":
                enterprise.setScale(toNullableText(value));
                return true;
            case "tax_qualification":
                profileRoot.put("tax_qualification", toNullableText(value));
                return true;
            default:
                break;
        }

        if (key.startsWith(PREF_PREFIX)) {
            String prefKey = key.substring(PREF_PREFIX.length());
            if (!StringUtils.hasText(prefKey)) {
                throw new BizException(ErrorCode.BAD_REQUEST, "偏好键不能为空：" + key);
            }
            if (!ALLOWED_PREFERENCE_KEYS.contains(prefKey)) {
                throw new BizException(ErrorCode.BAD_REQUEST, "不支持的偏好字段：" + prefKey);
            }
            String prefValue = toNullableText(value);
            validatePreferenceValue(prefKey, prefValue);
            if (prefValue == null) {
                preferences.remove(prefKey);
            } else {
                preferences.put(prefKey, prefValue);
            }
            return true;
        }

        log.debug("忽略未知的企业画像更新字段：{}", key);
        return false;
    }

    private void validatePreferenceValue(String prefKey, String value) {
        if (value == null) {
            return;
        }
        if ("settlement_cycle".equals(prefKey) && !ALLOWED_SETTLEMENT_CYCLES.contains(value)) {
            throw new BizException(ErrorCode.BAD_REQUEST,
                    "settlement_cycle 须为 daily/weekly/biweekly/monthly 之一");
        }
        if ("default_settlement_mode".equals(prefKey)) {
            Set<String> modes = new HashSet<>(Arrays.asList("daily", "piece", "monthly"));
            if (!modes.contains(value)) {
                throw new BizException(ErrorCode.BAD_REQUEST,
                        "default_settlement_mode 须为 daily/piece/monthly 之一");
            }
        }
    }

    private Map<String, Object> parseProfileJson(String profileJson) {
        if (!StringUtils.hasText(profileJson)) {
            return new LinkedHashMap<>();
        }
        try {
            Map<String, Object> parsed = objectMapper.readValue(profileJson.trim(),
                    new TypeReference<Map<String, Object>>() {
                    });
            return parsed != null ? new LinkedHashMap<>(parsed) : new LinkedHashMap<>();
        } catch (Exception ex) {
            log.warn("解析 profile_json 失败，将使用空对象：{}", ex.getMessage());
            return new LinkedHashMap<>();
        }
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> extractPreferences(Map<String, Object> profileRoot) {
        Object raw = profileRoot.get("preferences");
        if (raw instanceof Map) {
            return new LinkedHashMap<>((Map<String, Object>) raw);
        }
        return new LinkedHashMap<>();
    }

    private String writeProfileJson(Map<String, Object> profileRoot) {
        try {
            return objectMapper.writeValueAsString(profileRoot);
        } catch (Exception ex) {
            throw new BizException(ErrorCode.INTERNAL_ERROR);
        }
    }

    private static String requireNonBlankText(Object value, String key) {
        String text = toNullableText(value);
        if (text == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "字段 " + key + " 不能为空");
        }
        return text;
    }

    private static String toNullableText(Object value) {
        if (value == null) {
            return null;
        }
        String text = String.valueOf(value).trim();
        return text.isEmpty() ? null : text;
    }

    private static String readString(Object value) {
        return value != null ? String.valueOf(value) : null;
    }
}
