package com.huimv.employment.service.order;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.FeDraftField;
import com.huimv.employment.dao.entity.FeDraftWorkItem;
import com.huimv.employment.dao.entity.FeEmploymentDraft;
import com.huimv.employment.dao.entity.FeEmploymentOrder;
import com.huimv.employment.dao.entity.FeOrderWorkItem;
import com.huimv.employment.dao.mapper.FeDraftFieldMapper;
import com.huimv.employment.dao.mapper.FeEmploymentDraftMapper;
import com.huimv.employment.dao.mapper.FeEmploymentOrderMapper;
import com.huimv.employment.service.conversation.ConversationService;
import com.huimv.employment.service.draft.DraftSchemaRegistry;
import com.huimv.employment.service.draft.DraftWorkItemService;
import com.huimv.employment.service.draft.dto.DraftWorkerGroupItem;
import com.huimv.employment.service.order.dto.McpOrderCloneRequest;
import com.huimv.employment.service.order.dto.McpOrderCloneResponse;
import com.huimv.employment.service.order.dto.McpOrderListResponse;
import com.huimv.employment.service.order.dto.McpOrderSummaryItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * MCP 订单查询与克隆（v2 §6.3.6、§6.3.7）。
 */
@Service
public class McpOrderService {

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

    private static final String STATUS_SUCCESS = "success";
    private static final String DB_STATUS_PENDING = "pending";
    private static final String DB_STATUS_CANCELLED = "cancelled";
    private static final String SOURCE_HISTORY = "history_preference";
    private static final String DEFAULT_WORKER_SOURCE = "recruit";

    private static final int DEFAULT_LIMIT = 10;
    private static final int MAX_LIMIT = 50;

    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ISO_LOCAL_DATE;

    private final FeEmploymentOrderMapper feEmploymentOrderMapper;
    private final FeEmploymentDraftMapper feEmploymentDraftMapper;
    private final FeDraftFieldMapper feDraftFieldMapper;
    private final ConversationService conversationService;
    private final DraftWorkItemService draftWorkItemService;
    private final OrderWorkItemService orderWorkItemService;
    private final ObjectMapper objectMapper;

    public McpOrderService(FeEmploymentOrderMapper feEmploymentOrderMapper,
                           FeEmploymentDraftMapper feEmploymentDraftMapper,
                           FeDraftFieldMapper feDraftFieldMapper,
                           ConversationService conversationService,
                           DraftWorkItemService draftWorkItemService,
                           OrderWorkItemService orderWorkItemService,
                           ObjectMapper objectMapper) {
        this.feEmploymentOrderMapper = feEmploymentOrderMapper;
        this.feEmploymentDraftMapper = feEmploymentDraftMapper;
        this.feDraftFieldMapper = feDraftFieldMapper;
        this.conversationService = conversationService;
        this.draftWorkItemService = draftWorkItemService;
        this.orderWorkItemService = orderWorkItemService;
        this.objectMapper = objectMapper;
    }

    public McpOrderListResponse listOrders(String sessionId, String status, Integer limit) {
        FeConversation conversation = conversationService.requireBySessionId(sessionId);
        int resolvedLimit = resolveLimit(limit);

        LambdaQueryWrapper<FeEmploymentOrder> wrapper = new LambdaQueryWrapper<FeEmploymentOrder>()
                .eq(FeEmploymentOrder::getUserId, conversation.getUserId())
                .orderByDesc(FeEmploymentOrder::getCreateTime)
                .last("LIMIT " + resolvedLimit);
        if (StringUtils.hasText(status)) {
            wrapper.eq(FeEmploymentOrder::getOrderStatus, status.trim());
        }

        List<FeEmploymentOrder> orders = feEmploymentOrderMapper.selectList(wrapper);
        McpOrderListResponse response = new McpOrderListResponse();
        for (FeEmploymentOrder order : orders) {
            response.getOrders().add(toSummaryItem(order));
        }
        return response;
    }

    @Transactional(rollbackFor = Exception.class)
    public McpOrderCloneResponse cloneToDraft(String sessionId, McpOrderCloneRequest request) {
        FeConversation conversation = conversationService.requireBySessionId(sessionId);
        FeEmploymentOrder order = requireUserOrder(conversation.getUserId(), request.getOrderId());
        FeEmploymentDraft sourceDraft = order.getDraftId() != null
                ? feEmploymentDraftMapper.selectById(order.getDraftId()) : null;
        List<FeDraftWorkItem> sourceItems = sourceDraft != null
                ? draftWorkItemService.listByDraftId(sourceDraft.getId()) : Collections.emptyList();

        cancelPendingDrafts(conversation.getId());
        LocalDateTime now = LocalDateTime.now();
        FeEmploymentDraft draft = buildDraftFromOrder(conversation, order, sourceDraft, now);
        try {
            feEmploymentDraftMapper.insert(draft);
        } catch (DuplicateKeyException ex) {
            throw new BizException(ErrorCode.BAD_REQUEST, "草稿编号冲突，请重试");
        }
        draftWorkItemService.replaceAll(draft.getId(),
                buildWorkerGroupsFromOrder(order, sourceItems), now);
        syncClonedFieldMetadata(draft, now);
        recalculateMissingFields(draft, now);
        log.debug("订单 {} 已克隆为草稿 draftId={} session={}", order.getOrderNo(), draft.getId(), sessionId);

        McpOrderCloneResponse response = new McpOrderCloneResponse();
        response.setStatus(STATUS_SUCCESS);
        response.setDraftId(draft.getId());
        return response;
    }

    private FeEmploymentOrder requireUserOrder(Long userId, String orderId) {
        if (!StringUtils.hasText(orderId)) {
            throw new BizException(ErrorCode.BAD_REQUEST, "order_id 不能为空");
        }
        FeEmploymentOrder order = feEmploymentOrderMapper.selectOne(new LambdaQueryWrapper<FeEmploymentOrder>()
                .eq(FeEmploymentOrder::getOrderNo, orderId.trim())
                .last("LIMIT 1"));
        if (order == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "订单不存在");
        }
        if (userId == null || !userId.equals(order.getUserId())) {
            throw new BizException(ErrorCode.FORBIDDEN, "无权访问该订单");
        }
        return order;
    }

    private void cancelPendingDrafts(Long conversationId) {
        feEmploymentDraftMapper.update(null, new LambdaUpdateWrapper<FeEmploymentDraft>()
                .eq(FeEmploymentDraft::getConversationId, conversationId)
                .eq(FeEmploymentDraft::getStatus, DB_STATUS_PENDING)
                .set(FeEmploymentDraft::getStatus, DB_STATUS_CANCELLED)
                .set(FeEmploymentDraft::getUpdateTime, LocalDateTime.now()));
    }

    private FeEmploymentDraft buildDraftFromOrder(FeConversation conversation,
                                                  FeEmploymentOrder order,
                                                  FeEmploymentDraft sourceDraft,
                                                  LocalDateTime now) {
        FeEmploymentDraft draft = new FeEmploymentDraft();
        draft.setDraftNo(UUID.randomUUID().toString().replace("-", ""));
        draft.setEnterpriseId(order.getEnterpriseId());
        draft.setUserId(conversation.getUserId());
        draft.setConversationId(conversation.getId());
        draft.setStatus(DB_STATUS_PENDING);
        draft.setTitle(buildCloneTitle(order));
        if (sourceDraft != null && StringUtils.hasText(sourceDraft.getWorkerSource())) {
            draft.setWorkerSource(sourceDraft.getWorkerSource().trim().toLowerCase());
        } else {
            draft.setWorkerSource(DEFAULT_WORKER_SOURCE);
        }
        draft.setMissingFields("[]");
        draft.setRiskPrompts("[]");
        draft.setCreateTime(now);
        draft.setUpdateTime(now);
        return draft;
    }

    private List<DraftWorkerGroupItem> buildWorkerGroupsFromOrder(FeEmploymentOrder order,
                                                                  List<FeDraftWorkItem> sourceItems) {
        if (sourceItems != null && !sourceItems.isEmpty()) {
            return draftWorkItemService.toApiGroups(sourceItems);
        }
        return Collections.singletonList(buildWorkerGroupFromOrder(order, Collections.emptyList()));
    }

    private DraftWorkerGroupItem buildWorkerGroupFromOrder(FeEmploymentOrder order,
                                                           List<FeDraftWorkItem> sourceItems) {
        if (sourceItems != null && !sourceItems.isEmpty()) {
            return draftWorkItemService.toApiGroup(sourceItems.get(0));
        }
        FeOrderWorkItem first = orderWorkItemService.firstByOrderId(order.getId());
        DraftWorkerGroupItem group = new DraftWorkerGroupItem();
        group.setGroupId("grp_01");
        if (first != null) {
            group.setJobType(first.getJobType());
            group.setWorkerCount(first.getWorkerCount());
            group.setWorkDays(first.getWorkDays());
            group.setRegion(first.getWorkLocation());
            group.setSettlementCycle(StringUtils.hasText(first.getSettlementCycle())
                    ? first.getSettlementCycle() : null);
            group.setTotalAmount(first.getTotalAmount());
            group.setWorkStartDate(first.getWorkStartDate());
            group.setWorkEndDate(first.getWorkEndDate());
            group.setUnitAmount(first.getUnitAmount());
            group.setWorkContent(first.getWorkContent());
        } else {
            group.setWorkerCount(0);
        }
        return group;
    }

    private void syncClonedFieldMetadata(FeEmploymentDraft draft, LocalDateTime now) {
        Map<String, String> labels = DraftSchemaRegistry.fieldLabels();
        List<FeDraftWorkItem> items = draftWorkItemService.listByDraftId(draft.getId());
        upsertFieldIfPresent(draft.getId(), "worker_source", labels.get("worker_source"),
                draft.getWorkerSource(), now);
        try {
            upsertField(draft.getId(), "worker_groups", labels.get("worker_groups"),
                    objectMapper.writeValueAsString(draftWorkItemService.toApiGroups(items)),
                    now);
        } catch (Exception ex) {
            throw new BizException(ErrorCode.INTERNAL_ERROR);
        }
    }

    private void upsertFieldIfPresent(Long draftId, String fieldKey, String fieldLabel, Object value, LocalDateTime now) {
        if (value == null) {
            return;
        }
        String text = String.valueOf(value).trim();
        if (!StringUtils.hasText(text)) {
            return;
        }
        upsertField(draftId, fieldKey, fieldLabel, text, now);
    }

    private void upsertField(Long draftId, String fieldKey, String fieldLabel, String fieldValue, LocalDateTime now) {
        FeDraftField existing = feDraftFieldMapper.selectOne(new LambdaQueryWrapper<FeDraftField>()
                .eq(FeDraftField::getDraftId, draftId)
                .eq(FeDraftField::getFieldKey, fieldKey)
                .last("LIMIT 1"));
        if (existing != null) {
            FeDraftField update = new FeDraftField();
            update.setId(existing.getId());
            update.setFieldValue(fieldValue);
            update.setSource(SOURCE_HISTORY);
            update.setIsDefault(true);
            update.setUpdateTime(now);
            feDraftFieldMapper.updateById(update);
            return;
        }
        FeDraftField created = new FeDraftField();
        created.setDraftId(draftId);
        created.setFieldKey(fieldKey);
        created.setFieldLabel(fieldLabel);
        created.setFieldValue(fieldValue);
        created.setSource(SOURCE_HISTORY);
        created.setEditable(true);
        created.setIsDefault(true);
        created.setCreateTime(now);
        created.setUpdateTime(now);
        feDraftFieldMapper.insert(created);
    }

    private void recalculateMissingFields(FeEmploymentDraft draft, LocalDateTime now) {
        List<String> missing = new ArrayList<>();
        if (!StringUtils.hasText(draft.getWorkerSource())) {
            missing.add("worker_source");
        }
        List<FeDraftWorkItem> items = draftWorkItemService.listByDraftId(draft.getId());
        missing.addAll(draftWorkItemService.collectMissingGroupFields(items));
        try {
            FeEmploymentDraft update = new FeEmploymentDraft();
            update.setId(draft.getId());
            update.setMissingFields(objectMapper.writeValueAsString(missing));
            update.setUpdateTime(now);
            feEmploymentDraftMapper.updateById(update);
        } catch (Exception ex) {
            throw new BizException(ErrorCode.INTERNAL_ERROR);
        }
    }

    private McpOrderSummaryItem toSummaryItem(FeEmploymentOrder order) {
        McpOrderSummaryItem item = new McpOrderSummaryItem();
        item.setOrderId(order.getOrderNo());
        item.setSummary(buildSummary(order));
        item.setStatus(order.getOrderStatus());
        if (order.getCreateTime() != null) {
            item.setCreatedAt(order.getCreateTime().toLocalDate().format(DATE_FORMAT));
        }
        return item;
    }

    private String buildSummary(FeEmploymentOrder order) {
        List<FeOrderWorkItem> items = orderWorkItemService.listByOrderId(order.getId());
        int workers = orderWorkItemService.sumWorkerCount(items);
        java.math.BigDecimal total = orderWorkItemService.sumTotalAmount(items);
        if (total != null && total.compareTo(java.math.BigDecimal.ZERO) > 0) {
            String amount = total.stripTrailingZeros().toPlainString();
            return workers + "人/" + amount + "元";
        }
        if (StringUtils.hasText(order.getTitle())) {
            return order.getTitle();
        }
        return workers > 0 ? workers + "人" : "用工订单";
    }

    private static String buildCloneTitle(FeEmploymentOrder order) {
        if (StringUtils.hasText(order.getTitle())) {
            String title = order.getTitle().trim();
            return title.length() <= 200 ? title : title.substring(0, 200);
        }
        return "历史订单复用";
    }

    private static int resolveLimit(Integer limit) {
        if (limit == null || limit <= 0) {
            return DEFAULT_LIMIT;
        }
        return Math.min(limit, MAX_LIMIT);
    }
}
