package com.huimv.employment.service.conversation;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huimv.employment.dao.entity.FeEmploymentDraft;
import com.huimv.employment.dao.entity.FeEmploymentOrder;
import com.huimv.employment.dao.entity.FeRegistrationBatch;
import com.huimv.employment.dao.mapper.FeEmploymentDraftMapper;
import com.huimv.employment.dao.mapper.FeEmploymentOrderMapper;
import com.huimv.employment.dao.mapper.FeRegistrationBatchMapper;
import com.huimv.employment.service.conversation.dto.ParsedAssistantReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * SSE 最后消息时，由服务端注入卡片字段（不依赖智能体）。
 * <p>
 * 优先级：
 * 1）会话有 confirmed 订单且对应登记批次 {@code qr_code_url} 非空 → {@code card_order} / {@code show_order_qrcode}；
 * 2）否则会话有 pending 且 missingFields 为空的草稿 → {@code card_draft} / {@code show_employment_draft}。
 * </p>
 */
@Component
public class ConversationDraftCardEnricher {

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

    private static final String DB_STATUS_PENDING = "pending";
    private static final String ORDER_STATUS_CONFIRMED = "confirmed";

    private static final Pattern FENCED_CARD_BLOCK = Pattern.compile(
            "```(?:fe-card|json)?\\s*[\\s\\S]*?```",
            Pattern.CASE_INSENSITIVE);

    private final FeEmploymentDraftMapper feEmploymentDraftMapper;
    private final FeEmploymentOrderMapper feEmploymentOrderMapper;
    private final FeRegistrationBatchMapper feRegistrationBatchMapper;
    private final ObjectMapper objectMapper;

    public ConversationDraftCardEnricher(FeEmploymentDraftMapper feEmploymentDraftMapper,
                                         FeEmploymentOrderMapper feEmploymentOrderMapper,
                                         FeRegistrationBatchMapper feRegistrationBatchMapper,
                                         ObjectMapper objectMapper) {
        this.feEmploymentDraftMapper = feEmploymentDraftMapper;
        this.feEmploymentOrderMapper = feEmploymentOrderMapper;
        this.feRegistrationBatchMapper = feRegistrationBatchMapper;
        this.objectMapper = objectMapper;
    }

    /**
     * 按会话状态追加订单码卡片或草稿卡片。
     */
    public ParsedAssistantReply attachCardOnComplete(Long conversationId, String assistantText) {
        String displayText = sanitizeDisplayText(assistantText);
        ParsedAssistantReply parsed = ParsedAssistantReply.textOnly(displayText);
        if (conversationId == null) {
            log.warn("SSE 注入卡片跳过：conversationId 为空");
            return parsed;
        }

        ParsedAssistantReply withOrder = tryAttachOrderCard(conversationId, parsed);
        if (withOrder.hasCard()) {
            return withOrder;
        }
        return tryAttachDraftCard(conversationId, parsed);
    }

    private ParsedAssistantReply tryAttachOrderCard(Long conversationId, ParsedAssistantReply parsed) {
        ConfirmedOrderWithQr found = findLatestConfirmedOrderWithQr(conversationId);
        if (found == null) {
            log.info("SSE 注入订单卡片跳过：会话 {} 无 confirmed 订单或批次 qr_code_url 为空", conversationId);
            return parsed;
        }
        try {
            Map<String, Object> payload = buildOrderCardPayload(found.order, found.batch);
            String cardPayload = objectMapper.writeValueAsString(payload);
            log.info("SSE 注入订单卡片 conversationId={} orderNo={} batchId={} qr={}",
                    conversationId, found.order.getOrderNo(), found.batch.getId(), found.batch.getQrCodeUrl());
            return parsed.withCard(
                    MessageCardConstants.CONTENT_TYPE_CARD_ORDER,
                    MessageCardConstants.NEXT_ACTION_SHOW_ORDER_QRCODE,
                    cardPayload,
                    found.order.getDraftId());
        } catch (Exception ex) {
            log.warn("会话 {} 订单卡片注入失败: {}", conversationId, ex.getMessage(), ex);
            return parsed;
        }
    }

    private ParsedAssistantReply tryAttachDraftCard(Long conversationId, ParsedAssistantReply parsed) {
        FeEmploymentDraft draft = findPendingDraft(conversationId);
        if (draft == null) {
            log.info("SSE 注入草稿卡片跳过：会话 {} 无 pending 草稿", conversationId);
            return parsed;
        }
        List<String> missing = parseMissingFields(draft.getMissingFields());
        if (!missing.isEmpty()) {
            log.info("SSE 注入草稿卡片跳过：会话 {} 草稿 {} missingFields 非空 {}",
                    conversationId, draft.getId(), missing);
            return parsed;
        }
        try {
            Map<String, Object> payload = buildDraftCardPayload(draft);
            String cardPayload = objectMapper.writeValueAsString(payload);
            log.info("SSE 注入草稿卡片 conversationId={} draftId={}", conversationId, draft.getId());
            return parsed.withCard(
                    MessageCardConstants.CONTENT_TYPE_CARD_DRAFT,
                    MessageCardConstants.NEXT_ACTION_SHOW_EMPLOYMENT_DRAFT,
                    cardPayload,
                    draft.getId());
        } catch (Exception ex) {
            log.warn("会话 {} 草稿卡片注入失败: {}", conversationId, ex.getMessage(), ex);
            return parsed;
        }
    }

    private ConfirmedOrderWithQr findLatestConfirmedOrderWithQr(Long conversationId) {
        List<FeEmploymentDraft> drafts = feEmploymentDraftMapper.selectList(
                new LambdaQueryWrapper<FeEmploymentDraft>()
                        .eq(FeEmploymentDraft::getConversationId, conversationId)
                        .orderByDesc(FeEmploymentDraft::getId));
        if (drafts == null || drafts.isEmpty()) {
            return null;
        }
        List<Long> draftIds = new ArrayList<>(drafts.size());
        for (FeEmploymentDraft draft : drafts) {
            if (draft.getId() != null) {
                draftIds.add(draft.getId());
            }
        }
        if (draftIds.isEmpty()) {
            return null;
        }
        List<FeEmploymentOrder> orders = feEmploymentOrderMapper.selectList(
                new LambdaQueryWrapper<FeEmploymentOrder>()
                        .in(FeEmploymentOrder::getDraftId, draftIds)
                        .eq(FeEmploymentOrder::getOrderStatus, ORDER_STATUS_CONFIRMED)
                        .orderByDesc(FeEmploymentOrder::getId));
        if (orders == null || orders.isEmpty()) {
            return null;
        }
        for (FeEmploymentOrder order : orders) {
            FeRegistrationBatch batch = feRegistrationBatchMapper.selectOne(
                    new LambdaQueryWrapper<FeRegistrationBatch>()
                            .eq(FeRegistrationBatch::getOrderId, order.getId())
                            .isNotNull(FeRegistrationBatch::getQrCodeUrl)
                            .ne(FeRegistrationBatch::getQrCodeUrl, "")
                            .orderByDesc(FeRegistrationBatch::getId)
                            .last("LIMIT 1"));
            if (batch != null && StringUtils.hasText(batch.getQrCodeUrl())) {
                return new ConfirmedOrderWithQr(order, batch);
            }
        }
        return null;
    }

    private String sanitizeDisplayText(String raw) {
        if (!StringUtils.hasText(raw)) {
            return "";
        }
        String cleaned = FENCED_CARD_BLOCK.matcher(raw).replaceAll("").trim();
        return StringUtils.hasText(cleaned) ? cleaned : raw.trim();
    }

    private FeEmploymentDraft findPendingDraft(Long conversationId) {
        return feEmploymentDraftMapper.selectOne(new LambdaQueryWrapper<FeEmploymentDraft>()
                .eq(FeEmploymentDraft::getConversationId, conversationId)
                .eq(FeEmploymentDraft::getStatus, DB_STATUS_PENDING)
                .orderByDesc(FeEmploymentDraft::getCreateTime)
                .last("LIMIT 1"));
    }

    private List<String> parseMissingFields(String json) {
        if (!StringUtils.hasText(json)) {
            return Collections.emptyList();
        }
        try {
            List<String> parsed = objectMapper.readValue(json.trim(), new TypeReference<List<String>>() {
            });
            return parsed != null ? parsed : Collections.emptyList();
        } catch (Exception ex) {
            log.warn("解析 missing_fields 失败，视为非空，跳过注入: {}", ex.getMessage());
            return Collections.singletonList("_parse_error");
        }
    }

    private Map<String, Object> buildDraftCardPayload(FeEmploymentDraft draft) {
        Map<String, Object> payload = new LinkedHashMap<>();
        payload.put("draft_id", draft.getId());
        payload.put("draft_no", draft.getDraftNo());
        payload.put("title", draft.getTitle());
        payload.put("worker_count", draft.getWorkerCount());
        payload.put("work_days", draft.getWorkDays());
        payload.put("work_type", draft.getWorkType());
        payload.put("work_location", draft.getWorkLocation());
        payload.put("settlement_mode", draft.getSettlementMode());
        payload.put("total_amount", draft.getEstimatedTotal());
        payload.put("status", "ready");
        payload.put("missing_fields", Collections.emptyList());
        return payload;
    }

    private Map<String, Object> buildOrderCardPayload(FeEmploymentOrder order, FeRegistrationBatch batch) {
        Map<String, Object> payload = new LinkedHashMap<>();
        payload.put("draft_id", order.getDraftId());
        payload.put("order_id", order.getId());
        payload.put("order_no", order.getOrderNo());
        payload.put("title", order.getTitle());
        payload.put("worker_count", order.getWorkerCount());
        payload.put("work_days", order.getWorkDays());
        payload.put("work_type", order.getWorkType());
        payload.put("work_location", order.getWorkLocation());
        payload.put("work_start_date", order.getWorkStartDate());
        payload.put("work_end_date", order.getWorkEndDate());
        payload.put("order_status", order.getOrderStatus());
        payload.put("current_step_code", order.getCurrentStepCode());
        payload.put("registered_count", order.getRegisteredCount());
        payload.put("pending_count", order.getPendingCount());
        payload.put("total_outflow", order.getTotalOutflow());
        payload.put("batch_id", batch.getId());
        payload.put("batch_no", batch.getBatchNo());
        payload.put("qr_code_url", batch.getQrCodeUrl());
        payload.put("registration_url", batch.getRegistrationUrl());
        payload.put("qr_token", batch.getQrToken());
        return payload;
    }

    private static final class ConfirmedOrderWithQr {
        private final FeEmploymentOrder order;
        private final FeRegistrationBatch batch;

        private ConfirmedOrderWithQr(FeEmploymentOrder order, FeRegistrationBatch batch) {
            this.order = order;
            this.batch = batch;
        }
    }
}
