package com.huimv.employment.service.order;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.huimv.employment.common.exception.BizException;
import com.huimv.employment.common.exception.ErrorCode;
import com.huimv.employment.dao.entity.FeContract;
import com.huimv.employment.dao.entity.FeEmploymentDraft;
import com.huimv.employment.dao.entity.FeEmploymentOrder;
import com.huimv.employment.dao.entity.FeEnterprise;
import com.huimv.employment.dao.entity.FeOrderWorkItem;
import com.huimv.employment.dao.entity.FeRegistrationBatch;
import com.huimv.employment.dao.entity.FeWorkerRegistration;
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.dao.mapper.FeWorkerRegistrationMapper;
import com.huimv.employment.service.contract.ContractService;
import com.huimv.employment.service.conversation.ConversationService;
import com.huimv.employment.service.enterprise.EnterpriseService;
import com.huimv.employment.service.order.dto.EmploymentOrderItemResponse;
import com.huimv.employment.service.order.dto.OrderStartWorkRequest;
import com.huimv.employment.service.order.dto.OrderStartWorkResponse;
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.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 企业端用工订单：会话下订单列表、开工就绪查询与确认开工。
 * <p>
 * 当前暂时跳过签合同：登记 {@code completed} 即视为就绪。
 * 登记招满后自动推进到 {@code task_publish}；企业再调任务发布接口补齐起止日并生成结算单。
 * </p>
 */
@Service
public class EmploymentOrderService {

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

    /** 订单步骤：合同签署中（历史兼容） */
    private static final String STEP_CONTRACT_SIGNING = "contract_signing";
    /** 订单步骤：任务发布（登记招满后的目标步骤） */
    private static final String STEP_TASK_PUBLISH = "task_publish";
    /** 订单业务状态：进行中（登记招满 / 进入任务发布） */
    private static final String ORDER_STATUS_IN_PROGRESS = "in_progress";
    /** 批次状态：招满后关闭，不再接受新登记 */
    private static final String BATCH_STATUS_CLOSED = "closed";
    private static final String BATCH_STATUS_ACTIVE = "active";
    /** 登记：待签合同 */
    private static final String REG_CONTRACT_SIGNING = "contract_signing";
    /** 登记：已完成 */
    private static final String REG_COMPLETED = "completed";
    /** 登记：待企业审核（不阻挡齐签判定，但会计入提示） */
    private static final String REG_UNDER_REVIEW = "under_review";
    private static final String SIGN_SIGNED = "signed";

    private final FeEmploymentOrderMapper feEmploymentOrderMapper;
    private final FeEmploymentDraftMapper feEmploymentDraftMapper;
    private final FeWorkerRegistrationMapper feWorkerRegistrationMapper;
    private final FeRegistrationBatchMapper feRegistrationBatchMapper;
    private final ConversationService conversationService;
    private final EnterpriseService enterpriseService;
    private final ContractService contractService;
    private final OrderWorkItemService orderWorkItemService;

    public EmploymentOrderService(FeEmploymentOrderMapper feEmploymentOrderMapper,
                                  FeEmploymentDraftMapper feEmploymentDraftMapper,
                                  FeWorkerRegistrationMapper feWorkerRegistrationMapper,
                                  FeRegistrationBatchMapper feRegistrationBatchMapper,
                                  ConversationService conversationService,
                                  EnterpriseService enterpriseService,
                                  ContractService contractService,
                                  OrderWorkItemService orderWorkItemService) {
        this.feEmploymentOrderMapper = feEmploymentOrderMapper;
        this.feEmploymentDraftMapper = feEmploymentDraftMapper;
        this.feWorkerRegistrationMapper = feWorkerRegistrationMapper;
        this.feRegistrationBatchMapper = feRegistrationBatchMapper;
        this.conversationService = conversationService;
        this.enterpriseService = enterpriseService;
        this.contractService = contractService;
        this.orderWorkItemService = orderWorkItemService;
    }

    /**
     * 按会话查询其下草稿已转成正式订单的列表。
     * <p>仅返回已存在订单的草稿；无订单的草稿不出现在结果中。</p>
     */
    public List<EmploymentOrderItemResponse> listByConversation(Long userId, Long conversationId) {
        conversationService.requireOwned(userId, conversationId);
        FeEnterprise enterprise = enterpriseService.findEnterpriseByUserId(userId);
        if (enterprise == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "请先完成企业登记");
        }

        List<FeEmploymentDraft> drafts = feEmploymentDraftMapper.selectList(
                new LambdaQueryWrapper<FeEmploymentDraft>()
                        .eq(FeEmploymentDraft::getConversationId, conversationId)
                        .eq(FeEmploymentDraft::getEnterpriseId, enterprise.getId())
                        .orderByAsc(FeEmploymentDraft::getId));
        if (drafts == null || drafts.isEmpty()) {
            return Collections.emptyList();
        }

        List<Long> draftIds = new ArrayList<>(drafts.size());
        for (FeEmploymentDraft draft : drafts) {
            if (draft.getId() != null) {
                draftIds.add(draft.getId());
            }
        }
        if (draftIds.isEmpty()) {
            return Collections.emptyList();
        }

        List<FeEmploymentOrder> orders = feEmploymentOrderMapper.selectList(
                new LambdaQueryWrapper<FeEmploymentOrder>()
                        .eq(FeEmploymentOrder::getEnterpriseId, enterprise.getId())
                        .in(FeEmploymentOrder::getDraftId, draftIds)
                        .orderByDesc(FeEmploymentOrder::getCreateTime)
                        .orderByDesc(FeEmploymentOrder::getId));
        if (orders == null || orders.isEmpty()) {
            return Collections.emptyList();
        }

        List<EmploymentOrderItemResponse> result = new ArrayList<>(orders.size());
        for (FeEmploymentOrder order : orders) {
            result.add(toItem(order));
        }
        return result;
    }

    /**
     * 查询开工就绪状态（人数提示、是否齐签、是否可开工）。
     */
    public OrderStartWorkResponse getStartWorkStatus(Long userId, Long orderId) {
        FeEmploymentOrder order = requireOwnedOrder(userId, orderId);
        return buildStartWorkStatus(order, false);
    }

    /**
     * 历史「确认开工」接口：已改为提示走任务发布，不再写入 {@code work_started}。
     */
    @Transactional(rollbackFor = Exception.class)
    public OrderStartWorkResponse startWork(Long userId, Long orderId, OrderStartWorkRequest request) {
        FeEmploymentOrder order = requireOwnedOrder(userId, orderId);
        OrderStartWorkResponse status = buildStartWorkStatus(order, true);
        if (STEP_TASK_PUBLISH.equals(order.getCurrentStepCode())
                || isStepAfter(order.getCurrentStepCode(), STEP_TASK_PUBLISH)) {
            status.setMessage("订单已进入任务发布或后续阶段");
            return status;
        }
        throw new BizException(ErrorCode.BAD_REQUEST,
                "请调用任务发布接口（POST /api/v1/mp/orders/{orderId}/publish-task）推进到 task_publish");
    }

    /**
     * 登记招满后同步更新订单与批次：
     * <ul>
     *   <li>订单 {@code current_step_code=task_publish}、{@code order_status=in_progress}</li>
     *   <li>登记批次 {@code status=closed}（不再接受新登记）、{@code pending_count=0}</li>
     * </ul>
     *
     * @return true 表示本次有状态变更
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean tryAutoStartWorkWhenFullySigned(Long orderId) {
        if (orderId == null) {
            return false;
        }
        FeEmploymentOrder order = feEmploymentOrderMapper.selectById(orderId);
        if (order == null) {
            return false;
        }

        int planned = orderWorkItemService.sumWorkerCountByOrderId(orderId);
        if (planned <= 0) {
            return false;
        }
        Long completed = feWorkerRegistrationMapper.selectCount(
                new LambdaQueryWrapper<FeWorkerRegistration>()
                        .eq(FeWorkerRegistration::getOrderId, orderId)
                        .eq(FeWorkerRegistration::getRegStatus, REG_COMPLETED));
        int ready = completed != null ? completed.intValue() : 0;
        if (ready < planned) {
            log.debug("登记未招满，不推进 task_publish orderId={} ready={}/{}",
                    orderId, ready, planned);
            return false;
        }

        LocalDateTime now = LocalDateTime.now();
        boolean changed = false;

        boolean alreadyAtOrAfterPublish = STEP_TASK_PUBLISH.equals(order.getCurrentStepCode())
                || isStepAfter(order.getCurrentStepCode(), STEP_TASK_PUBLISH);
        boolean needOrderStatus = !ORDER_STATUS_IN_PROGRESS.equals(order.getOrderStatus())
                && !"settling".equals(order.getOrderStatus())
                && !"paid".equals(order.getOrderStatus())
                && !"completed".equals(order.getOrderStatus());
        if (!alreadyAtOrAfterPublish || needOrderStatus) {
            FeEmploymentOrder update = new FeEmploymentOrder();
            update.setId(orderId);
            if (!alreadyAtOrAfterPublish) {
                update.setCurrentStepCode(STEP_TASK_PUBLISH);
                order.setCurrentStepCode(STEP_TASK_PUBLISH);
            }
            if (needOrderStatus) {
                update.setOrderStatus(ORDER_STATUS_IN_PROGRESS);
                order.setOrderStatus(ORDER_STATUS_IN_PROGRESS);
            }
            update.setUpdateTime(now);
            feEmploymentOrderMapper.updateById(update);
            changed = true;
        }

        if (closeBatchesWhenFull(orderId, planned, ready, now)) {
            changed = true;
        }

        if (changed) {
            log.info("登记已招满，更新订单与批次状态 orderId={} step={} orderStatus={} ready={}/{}",
                    orderId, order.getCurrentStepCode(), order.getOrderStatus(), ready, planned);
        }
        return changed;
    }

    /**
     * 标记人员登记/招聘完成：订单推进到 {@code task_publish}，关闭登记批次。
     * <p>用于第三方平台工人添加成功后，不依赖是否招满计划人数。</p>
     *
     * @return true 表示本次有状态变更
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean markRegistrationCompleted(Long orderId) {
        if (orderId == null) {
            return false;
        }
        FeEmploymentOrder order = feEmploymentOrderMapper.selectById(orderId);
        if (order == null) {
            return false;
        }
        Long completed = feWorkerRegistrationMapper.selectCount(
                new LambdaQueryWrapper<FeWorkerRegistration>()
                        .eq(FeWorkerRegistration::getOrderId, orderId)
                        .eq(FeWorkerRegistration::getRegStatus, REG_COMPLETED));
        int ready = completed != null ? completed.intValue() : 0;
        if (ready <= 0) {
            log.warn("无已完成登记工人，不标记人员登记完成 orderId={}", orderId);
            return false;
        }
        int planned = orderWorkItemService.sumWorkerCountByOrderId(orderId);
        LocalDateTime now = LocalDateTime.now();
        boolean changed = false;

        boolean alreadyAtOrAfterPublish = STEP_TASK_PUBLISH.equals(order.getCurrentStepCode())
                || isStepAfter(order.getCurrentStepCode(), STEP_TASK_PUBLISH);
        boolean needOrderStatus = !ORDER_STATUS_IN_PROGRESS.equals(order.getOrderStatus())
                && !"settling".equals(order.getOrderStatus())
                && !"paid".equals(order.getOrderStatus())
                && !"completed".equals(order.getOrderStatus());
        if (!alreadyAtOrAfterPublish || needOrderStatus) {
            FeEmploymentOrder update = new FeEmploymentOrder();
            update.setId(orderId);
            if (!alreadyAtOrAfterPublish) {
                update.setCurrentStepCode(STEP_TASK_PUBLISH);
                order.setCurrentStepCode(STEP_TASK_PUBLISH);
            }
            if (needOrderStatus) {
                update.setOrderStatus(ORDER_STATUS_IN_PROGRESS);
                order.setOrderStatus(ORDER_STATUS_IN_PROGRESS);
            }
            update.setUpdateTime(now);
            feEmploymentOrderMapper.updateById(update);
            changed = true;
        }
        if (closeBatchesWhenFull(orderId, planned > 0 ? planned : ready, ready, now)) {
            changed = true;
        }
        if (changed) {
            log.info("人员登记已标记完成 orderId={} step={} ready={}",
                    orderId, order.getCurrentStepCode(), ready);
        }
        return changed;
    }

    /** 招满后关闭本单下仍为 active 的登记批次。 */
    private boolean closeBatchesWhenFull(Long orderId, int planned, int ready, LocalDateTime now) {
        List<FeRegistrationBatch> batches = feRegistrationBatchMapper.selectList(
                new LambdaQueryWrapper<FeRegistrationBatch>()
                        .eq(FeRegistrationBatch::getOrderId, orderId)
                        .eq(FeRegistrationBatch::getStatus, BATCH_STATUS_ACTIVE));
        if (batches == null || batches.isEmpty()) {
            return false;
        }
        boolean changed = false;
        for (FeRegistrationBatch batch : batches) {
            FeRegistrationBatch update = new FeRegistrationBatch();
            update.setId(batch.getId());
            update.setStatus(BATCH_STATUS_CLOSED);
            update.setPendingCount(0);
            update.setCompletedCount(ready);
            update.setRegisteredCount(Math.max(
                    batch.getRegisteredCount() != null ? batch.getRegisteredCount() : 0, ready));
            if (batch.getExpectedCount() == null || batch.getExpectedCount() <= 0) {
                update.setExpectedCount(planned);
            }
            update.setUpdateTime(now);
            feRegistrationBatchMapper.updateById(update);
            changed = true;
        }
        return changed;
    }

    /** 校验企业身份且订单归属当前企业。 */
    private FeEmploymentOrder requireOwnedOrder(Long userId, Long orderId) {
        enterpriseService.requireEnterpriseUser(userId);
        FeEnterprise enterprise = enterpriseService.findEnterpriseByUserId(userId);
        if (enterprise == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "请先完成企业登记");
        }
        if (orderId == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "订单 ID 无效");
        }
        FeEmploymentOrder order = feEmploymentOrderMapper.selectById(orderId);
        if (order == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "用工订单不存在");
        }
        if (order.getEnterpriseId() == null || !order.getEnterpriseId().equals(enterprise.getId())) {
            throw new BizException(ErrorCode.FORBIDDEN, "无权操作该订单");
        }
        return order;
    }

    /**
     * 统计本单开工就绪指标。
     * <ul>
     *   <li>approved：已加入链路（contract_signing / completed）</li>
     *   <li>signed/ready：{@code completed}，或合同已 signed（兼容旧数据）</li>
     *   <li>under_review：仅提示</li>
     *   <li>understaffed：就绪人数 &lt; 计划人数</li>
     * </ul>
     */
    private OrderStartWorkResponse buildStartWorkStatus(FeEmploymentOrder order, boolean forStartAction) {
        Long orderId = order.getId();
        int planned = orderWorkItemService.sumWorkerCountByOrderId(orderId);

        List<FeWorkerRegistration> regs = feWorkerRegistrationMapper.selectList(
                new LambdaQueryWrapper<FeWorkerRegistration>()
                        .eq(FeWorkerRegistration::getOrderId, orderId));
        if (regs == null) {
            regs = Collections.emptyList();
        }

        int approved = 0;
        int signed = 0;
        int pendingSign = 0;
        int underReview = 0;
        for (FeWorkerRegistration reg : regs) {
            String st = reg.getRegStatus();
            if (REG_UNDER_REVIEW.equals(st)) {
                underReview++;
                continue;
            }
            if (!REG_CONTRACT_SIGNING.equals(st) && !REG_COMPLETED.equals(st)) {
                continue;
            }
            approved++;
            // 跳过签合同：completed 即视为就绪；仍兼容旧合同 signed
            if (REG_COMPLETED.equals(st)) {
                signed++;
                continue;
            }
            FeContract contract = contractService.findActiveByRegistrationId(reg.getId());
            if (contract != null && SIGN_SIGNED.equals(contract.getSignStatus())) {
                signed++;
            } else {
                pendingSign++;
            }
        }

        boolean allApprovedSigned = approved > 0 && pendingSign == 0;
        boolean understaffed = planned > 0 && signed < planned;
        boolean atSigning = STEP_CONTRACT_SIGNING.equals(order.getCurrentStepCode());
        boolean canStart = atSigning && allApprovedSigned;

        OrderStartWorkResponse response = new OrderStartWorkResponse();
        response.setOrderId(orderId);
        response.setOrderNo(order.getOrderNo());
        response.setCurrentStepCode(order.getCurrentStepCode());
        response.setPlannedCount(planned);
        response.setApprovedCount(approved);
        response.setSignedCount(signed);
        response.setPendingSignCount(pendingSign);
        response.setUnderReviewCount(underReview);
        response.setAllApprovedSigned(allApprovedSigned);
        response.setUnderstaffed(understaffed);
        response.setCanStartWork(canStart);

        if (STEP_TASK_PUBLISH.equals(order.getCurrentStepCode())
                || isStepAfter(order.getCurrentStepCode(), STEP_TASK_PUBLISH)) {
            response.setMessage("订单已进入任务发布或后续阶段");
        } else if (!atSigning) {
            response.setMessage("订单尚未进入可任务发布阶段，请调用任务发布接口");
        } else if (approved == 0) {
            response.setMessage("尚无已加入工人");
        } else if (!allApprovedSigned) {
            response.setMessage("已就绪 " + signed + "/" + approved + "，待处理 " + pendingSign + " 人");
        } else if (understaffed) {
            response.setMessage("人员已就绪，但未招满（已加入 " + signed + "/" + planned
                    + "）。任务发布缺编须传 allow_understaffed=true"
                    + (underReview > 0 ? "；另有 " + underReview + " 人待审" : ""));
        } else {
            response.setMessage("人数已达标，可调用任务发布接口"
                    + (underReview > 0 ? "（另有 " + underReview + " 人待审）" : ""));
        }
        return response;
    }

    /** 判断 current 是否在流程中严格位于 target 之后。 */
    private static boolean isStepAfter(String current, String target) {
        if (!StringUtils.hasText(current) || !StringUtils.hasText(target)) {
            return false;
        }
        String[] steps = {
                "draft", "draft_created", "plan_confirmed", "enterprise_auth",
                "registration", "worker_registration", "worker_recruitment",
                "enterprise_audit", "contract_signing",
                "task_publish", "settlement_pending", "settlement",
                "settlement_paid", "invoice_archive", "completed"
        };
        int curIdx = -1;
        int targetIdx = -1;
        for (int i = 0; i < steps.length; i++) {
            if (steps[i].equals(current)) {
                curIdx = i;
            }
            if (steps[i].equals(target)) {
                targetIdx = i;
            }
        }
        return curIdx >= 0 && targetIdx >= 0 && curIdx > targetIdx;
    }

    private EmploymentOrderItemResponse toItem(FeEmploymentOrder order) {
        List<FeOrderWorkItem> items = orderWorkItemService.listByOrderId(order.getId());
        FeOrderWorkItem first = orderWorkItemService.firstItem(items);
        EmploymentOrderItemResponse item = new EmploymentOrderItemResponse();
        item.setDraftId(order.getDraftId());
        item.setOrderId(order.getId());
        item.setOrderNo(order.getOrderNo());
        item.setTitle(order.getTitle());
        item.setWorkerCount(orderWorkItemService.sumWorkerCount(items));
        item.setWorkDays(first != null ? first.getWorkDays() : null);
        item.setWorkType(first != null ? first.getJobType() : null);
        item.setWorkLocation(first != null ? first.getWorkLocation() : null);
        item.setWorkStartDate(first != null ? first.getWorkStartDate() : null);
        item.setWorkEndDate(orderWorkItemService.maxWorkEndDate(items));
        item.setOrderStatus(order.getOrderStatus());
        item.setCurrentStepCode(order.getCurrentStepCode());
        item.setRegisteredCount(null);
        item.setPendingCount(null);
        item.setAbnormalCount(null);
        item.setTotalOutflow(orderWorkItemService.sumTotalAmount(items));
        item.setSelectedPlanId(order.getSelectedPlanId());
        item.setCreateTime(order.getCreateTime());
        item.setUpdateTime(order.getUpdateTime());
        return item;
    }
}
