package com.huimv.employment.service.registration;

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.common.util.AesUtils;
import com.huimv.employment.common.util.IdCardUtils;
import com.huimv.employment.common.util.MobileUtils;
import com.huimv.employment.dao.entity.FeEmploymentOrder;
import com.huimv.employment.dao.entity.FeEnterprise;
import com.huimv.employment.dao.entity.FeRegistrationBatch;
import com.huimv.employment.dao.entity.FeWorker;
import com.huimv.employment.dao.entity.FeWorkerRegistration;
import com.huimv.employment.dao.entity.FeOrderWorkItem;
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.config.SecurityProperties;
import com.huimv.employment.service.enterprise.EnterpriseService;
import com.huimv.employment.service.order.EmploymentOrderService;
import com.huimv.employment.service.order.OrderWorkItemService;
import com.huimv.employment.service.registration.dto.ThirdPartyWorkerAddItem;
import com.huimv.employment.service.registration.dto.ThirdPartyWorkersAddRequest;
import com.huimv.employment.service.registration.dto.ThirdPartyWorkersAddResponse;
import com.huimv.employment.service.registration.dto.WorkerRegistrationApplyRequest;
import com.huimv.employment.service.registration.dto.WorkerRegistrationApplyResponse;
import com.huimv.employment.service.registration.dto.WorkerRegistrationRejectRequest;
import com.huimv.employment.service.registration.dto.WorkerRegistrationReviewResponse;
import com.huimv.employment.service.worker.WorkerService;
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.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 用工邀请 / 批次登记：临时工扫码申请。
 * <p>当前策略：无需企业审核、无需签合同；申请成功即 {@code reg_status=completed}，
 * 招满后自动将订单 {@code current_step_code} 推进到 {@code task_publish}。</p>
 */
@Service
public class WorkerRegistrationService {

    private static final String BATCH_ACTIVE = "active";
    private static final String REG_UNDER_REVIEW = "under_review";
    private static final String REG_CONTRACT_SIGNING = "contract_signing";
    private static final String REG_COMPLETED = "completed";
    private static final String REG_REJECTED = "rejected";
    private static final String APPLY_SUCCESS = "success";
    private static final String APPLY_ALREADY = "already_applied";
    /** 订单临时工来源：无临时工 → 第三方人力平台匹配 */
    private static final String WORKER_SOURCE_RECRUIT = "recruit";
    private static final int THIRD_PARTY_NO = 0;
    private static final int THIRD_PARTY_YES = 1;

    private final FeRegistrationBatchMapper feRegistrationBatchMapper;
    private final FeEmploymentOrderMapper feEmploymentOrderMapper;
    private final FeWorkerRegistrationMapper feWorkerRegistrationMapper;
    private final WorkerService workerService;
    private final EmploymentOrderService employmentOrderService;
    private final OrderWorkItemService orderWorkItemService;
    private final EnterpriseService enterpriseService;
    private final SecurityProperties securityProperties;

    public WorkerRegistrationService(FeRegistrationBatchMapper feRegistrationBatchMapper,
                                     FeEmploymentOrderMapper feEmploymentOrderMapper,
                                     FeWorkerRegistrationMapper feWorkerRegistrationMapper,
                                     WorkerService workerService,
                                     EmploymentOrderService employmentOrderService,
                                     OrderWorkItemService orderWorkItemService,
                                     EnterpriseService enterpriseService,
                                     SecurityProperties securityProperties) {
        this.feRegistrationBatchMapper = feRegistrationBatchMapper;
        this.feEmploymentOrderMapper = feEmploymentOrderMapper;
        this.feWorkerRegistrationMapper = feWorkerRegistrationMapper;
        this.workerService = workerService;
        this.employmentOrderService = employmentOrderService;
        this.orderWorkItemService = orderWorkItemService;
        this.enterpriseService = enterpriseService;
        this.securityProperties = securityProperties;
    }

    /**
     * 临时工申请加入用工邀请（scene = 订单编号）。
     * <p>要求已完成档案登记。无需审核、无需签合同，直接 {@code completed}。
     * 历史 {@code under_review}/{@code contract_signing} 再申请时自动完结。</p>
     */
    @Transactional(rollbackFor = Exception.class)
    public WorkerRegistrationApplyResponse apply(Long userId, WorkerRegistrationApplyRequest request) {
        workerService.requireWorkerUser(userId);
        if (request == null || !StringUtils.hasText(request.getScene())) {
            throw new BizException(ErrorCode.BAD_REQUEST, "scene 不能为空");
        }
        FeWorker worker = workerService.findWorkerByUserId(userId);
        if (worker == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "请先完成临时工档案登记");
        }

        String scene = request.getScene().trim();
        FeRegistrationBatch batch = requireActiveBatchByScene(scene);
        requireBatchEnterprise(batch);
        FeEmploymentOrder order = feEmploymentOrderMapper.selectById(batch.getOrderId());
        if (order == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "用工订单不存在");
        }

        String confirmedWorkType = requireOrderJobType(order.getId(), request.getConfirmedWorkType());

        FeWorkerRegistration existing = feWorkerRegistrationMapper.selectOne(new LambdaQueryWrapper<FeWorkerRegistration>()
                .eq(FeWorkerRegistration::getBatchId, batch.getId())
                .eq(FeWorkerRegistration::getWorkerId, worker.getId())
                .orderByDesc(FeWorkerRegistration::getId)
                .last("LIMIT 1"));
        if (existing != null) {
            if (REG_REJECTED.equals(existing.getRegStatus())) {
                return toResponse(existing, batch, order, APPLY_ALREADY, "您的申请已被驳回，如有疑问请联系企业");
            }
            if (REG_COMPLETED.equals(existing.getRegStatus())) {
                return toResponse(existing, batch, order, APPLY_ALREADY, "您已加入该用工");
            }
            // 历史待审 / 待签：直接完结（无合同流程）
            LocalDateTime now = LocalDateTime.now();
            completeRegistrationWithoutContract(existing, batch, order, now);
            order = feEmploymentOrderMapper.selectById(order.getId());
            return toResponse(existing, batch, order, APPLY_SUCCESS, "已加入用工");
        }

        assertBatchHasCapacity(batch);

        LocalDateTime now = LocalDateTime.now();
        FeWorkerRegistration reg = new FeWorkerRegistration();
        reg.setBatchId(batch.getId());
        reg.setOrderId(order.getId());
        reg.setEnterpriseId(batch.getEnterpriseId());
        reg.setWorkerId(worker.getId());
        reg.setRealName(worker.getRealName());
        reg.setMobileEnc(worker.getMobileEnc());
        reg.setMobileMask(worker.getMobileMask());
        reg.setIdCardNoEnc(worker.getIdCardNoEnc());
        reg.setBankAccountEnc(worker.getBankAccountEnc());
        reg.setConfirmedWorkType(confirmedWorkType);
        reg.setThirdPartySource(resolveThirdPartySource(order));
        reg.setRegStatus(REG_COMPLETED);
        reg.setSubmittedAt(now);
        reg.setReviewedAt(now);
        reg.setRemindCount(0);
        reg.setCreateTime(now);
        reg.setUpdateTime(now);
        reg.setDelFlag(0);
        feWorkerRegistrationMapper.insert(reg);

        bumpBatchCounters(batch, now);
        bumpCompletedCounters(batch, now);
        employmentOrderService.tryAutoStartWorkWhenFullySigned(order.getId());

        order = feEmploymentOrderMapper.selectById(order.getId());
        return toResponse(reg, batch, order, APPLY_SUCCESS, "已加入用工");
    }

    /**
     * 企业添加第三方平台工人到登记批次。
     * <p>写入 {@code fe_worker_registration}（{@code third_party_source=1}、{@code reg_status=completed}），
     * 成功后标记人员登记/招聘完成（订单推进 {@code task_publish}，关闭批次）。</p>
     */
    @Transactional(rollbackFor = Exception.class)
    public ThirdPartyWorkersAddResponse addThirdPartyWorkers(Long userId, ThirdPartyWorkersAddRequest request) {
        enterpriseService.requireEnterpriseUser(userId);
        if (request == null || request.getBatchId() == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "batch_id 不能为空");
        }
        if (request.getWorkers() == null || request.getWorkers().isEmpty()) {
            throw new BizException(ErrorCode.BAD_REQUEST, "workers 不能为空");
        }

        FeEnterprise enterprise = enterpriseService.findEnterpriseByUserId(userId);
        if (enterprise == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "请先完成企业登记");
        }

        FeRegistrationBatch batch = feRegistrationBatchMapper.selectById(request.getBatchId());
        if (batch == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "登记批次不存在");
        }
        requireBatchEnterprise(batch);
        if (batch.getEnterpriseId() == null || !batch.getEnterpriseId().equals(enterprise.getId())) {
            throw new BizException(ErrorCode.FORBIDDEN, "无权操作该登记批次");
        }
        if (!BATCH_ACTIVE.equals(batch.getStatus())) {
            throw new BizException(ErrorCode.BAD_REQUEST, "该登记批次已关闭或失效，无法添加工人");
        }

        FeEmploymentOrder order = feEmploymentOrderMapper.selectById(batch.getOrderId());
        if (order == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "用工订单不存在");
        }

        LocalDateTime now = LocalDateTime.now();
        List<Long> addedIds = new ArrayList<>();
        int skipped = 0;
        Set<Long> seenWorkerIds = new HashSet<>();

        for (ThirdPartyWorkerAddItem item : request.getWorkers()) {
            if (item == null) {
                continue;
            }
            if (!StringUtils.hasText(item.getRealName())) {
                throw new BizException(ErrorCode.BAD_REQUEST, "workers 中 real_name 不能为空");
            }
            if (!StringUtils.hasText(item.getMobile())) {
                throw new BizException(ErrorCode.BAD_REQUEST, "workers 中 mobile 不能为空");
            }
            if (!StringUtils.hasText(item.getIdCardNo())) {
                throw new BizException(ErrorCode.BAD_REQUEST, "workers 中 id_card_no 不能为空");
            }
            String workType = requireOrderJobType(order.getId(), item.getConfirmedWorkType());
            String mobile = item.getMobile().trim();
            MobileUtils.validate(mobile);
            String idCardNo = item.getIdCardNo().trim().toUpperCase();
            IdCardUtils.validate(idCardNo);

            String aesKey = securityProperties.getMobileAesKey();
            String mobileEnc = AesUtils.encrypt(mobile, aesKey);
            String mobileMask = MobileUtils.mask(mobile);
            String idCardNoEnc = AesUtils.encrypt(idCardNo, aesKey);

            Long workerId = item.getWorkerId();
            if (workerId != null) {
                if (!seenWorkerIds.add(workerId)) {
                    skipped++;
                    continue;
                }
                FeWorkerRegistration existing = feWorkerRegistrationMapper.selectOne(
                        new LambdaQueryWrapper<FeWorkerRegistration>()
                                .eq(FeWorkerRegistration::getBatchId, batch.getId())
                                .eq(FeWorkerRegistration::getWorkerId, workerId)
                                .eq(FeWorkerRegistration::getThirdPartySource, THIRD_PARTY_YES)
                                .orderByDesc(FeWorkerRegistration::getId)
                                .last("LIMIT 1"));
                if (existing != null && REG_COMPLETED.equals(existing.getRegStatus())) {
                    skipped++;
                    continue;
                }
            } else {
                // 无 worker_id 时按同批次手机密文去重
                FeWorkerRegistration existingByMobile = feWorkerRegistrationMapper.selectOne(
                        new LambdaQueryWrapper<FeWorkerRegistration>()
                                .eq(FeWorkerRegistration::getBatchId, batch.getId())
                                .eq(FeWorkerRegistration::getMobileEnc, mobileEnc)
                                .eq(FeWorkerRegistration::getThirdPartySource, THIRD_PARTY_YES)
                                .orderByDesc(FeWorkerRegistration::getId)
                                .last("LIMIT 1"));
                if (existingByMobile != null && REG_COMPLETED.equals(existingByMobile.getRegStatus())) {
                    skipped++;
                    continue;
                }
            }

            FeWorkerRegistration reg = new FeWorkerRegistration();
            reg.setBatchId(batch.getId());
            reg.setOrderId(order.getId());
            reg.setEnterpriseId(batch.getEnterpriseId());
            reg.setWorkerId(workerId);
            reg.setRealName(item.getRealName().trim());
            reg.setMobileEnc(mobileEnc);
            reg.setMobileMask(mobileMask);
            reg.setIdCardNoEnc(idCardNoEnc);
            reg.setConfirmedWorkType(workType);
            reg.setThirdPartySource(THIRD_PARTY_YES);
            reg.setRegStatus(REG_COMPLETED);
            reg.setSubmittedAt(now);
            reg.setReviewedAt(now);
            reg.setRemindCount(0);
            reg.setCreateTime(now);
            reg.setUpdateTime(now);
            reg.setDelFlag(0);
            feWorkerRegistrationMapper.insert(reg);

            bumpBatchCounters(batch, now);
            bumpCompletedCounters(batch, now);
            // 本地计数同步，便于同批次连续插入
            batch.setRegisteredCount((batch.getRegisteredCount() != null ? batch.getRegisteredCount() : 0) + 1);
            int pending = batch.getPendingCount() != null ? batch.getPendingCount() : 0;
            batch.setPendingCount(Math.max(0, pending - 1));

            addedIds.add(reg.getId());
        }

        if (addedIds.isEmpty() && skipped == 0) {
            throw new BizException(ErrorCode.BAD_REQUEST, "无有效工人可添加");
        }

        // 成功添加后标记人员登记/招聘完成
        boolean completed = false;
        if (!addedIds.isEmpty() || hasCompletedRegistration(order.getId())) {
            completed = employmentOrderService.markRegistrationCompleted(order.getId());
            if (!completed) {
                // 已在 task_publish 及之后也视为完成
                FeEmploymentOrder refreshed = feEmploymentOrderMapper.selectById(order.getId());
                completed = refreshed != null && (
                        "task_publish".equals(refreshed.getCurrentStepCode())
                                || isStepAtOrAfterTaskPublish(refreshed.getCurrentStepCode()));
            }
        }

        FeEmploymentOrder refreshed = feEmploymentOrderMapper.selectById(order.getId());
        ThirdPartyWorkersAddResponse response = new ThirdPartyWorkersAddResponse();
        response.setBatchId(batch.getId());
        response.setBatchNo(batch.getBatchNo());
        response.setOrderId(order.getId());
        response.setOrderNo(order.getOrderNo());
        response.setAddedCount(addedIds.size());
        response.setSkippedCount(skipped);
        response.setRegistrationIds(addedIds);
        response.setCurrentStepCode(refreshed != null ? refreshed.getCurrentStepCode() : order.getCurrentStepCode());
        response.setRegistrationCompleted(completed
                || (refreshed != null && isStepAtOrAfterTaskPublish(refreshed.getCurrentStepCode())));
        response.setMessage(addedIds.isEmpty()
                ? "工人均已存在，未新增；人员登记状态已同步"
                : "已添加 " + addedIds.size() + " 名第三方工人，人员登记已完成");
        return response;
    }

    private boolean hasCompletedRegistration(Long orderId) {
        Long count = feWorkerRegistrationMapper.selectCount(
                new LambdaQueryWrapper<FeWorkerRegistration>()
                        .eq(FeWorkerRegistration::getOrderId, orderId)
                        .eq(FeWorkerRegistration::getRegStatus, REG_COMPLETED));
        return count != null && count > 0;
    }

    private static boolean isStepAtOrAfterTaskPublish(String step) {
        if (!StringUtils.hasText(step)) {
            return false;
        }
        if ("task_publish".equals(step)) {
            return true;
        }
        String[] after = {
                "settlement_pending", "settlement", "settlement_paid", "invoice_archive", "completed"
        };
        for (String s : after) {
            if (s.equals(step)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 企业审核通过（已暂时停用）。
     */
    @Transactional(rollbackFor = Exception.class)
    public WorkerRegistrationReviewResponse approve(Long userId, Long registrationId) {
        throw new BizException(ErrorCode.BAD_REQUEST, "企业审核已暂时关闭，用工申请无需审核");
    }

    /**
     * 企业驳回（已暂时停用）。
     */
    @Transactional(rollbackFor = Exception.class)
    public WorkerRegistrationReviewResponse reject(Long userId, Long registrationId,
                                                   WorkerRegistrationRejectRequest request) {
        throw new BizException(ErrorCode.BAD_REQUEST, "企业审核已暂时关闭，用工申请无需审核");
    }

    /**
     * 将历史 under_review / contract_signing 直接完结（不创建合同）。
     */
    private void completeRegistrationWithoutContract(FeWorkerRegistration reg,
                                                     FeRegistrationBatch batch,
                                                     FeEmploymentOrder order,
                                                     LocalDateTime now) {
        String prev = reg.getRegStatus();
        if (REG_COMPLETED.equals(prev)) {
            return;
        }

        FeWorkerRegistration update = new FeWorkerRegistration();
        update.setId(reg.getId());
        update.setRegStatus(REG_COMPLETED);
        update.setFailReason(null);
        update.setReviewedAt(reg.getReviewedAt() != null ? reg.getReviewedAt() : now);
        update.setUpdateTime(now);
        feWorkerRegistrationMapper.updateById(update);

        reg.setRegStatus(REG_COMPLETED);
        reg.setFailReason(null);
        reg.setUpdateTime(now);

        // under_review 从未计入 completed_count；contract_signing 申请时已计入，勿重复
        if (REG_UNDER_REVIEW.equals(prev)) {
            bumpCompletedCounters(batch, now);
        }
        employmentOrderService.tryAutoStartWorkWhenFullySigned(order.getId());
    }

    private void bumpCompletedCounters(FeRegistrationBatch batch, LocalDateTime now) {
        int completed = batch.getCompletedCount() != null ? batch.getCompletedCount() : 0;
        FeRegistrationBatch update = new FeRegistrationBatch();
        update.setId(batch.getId());
        update.setCompletedCount(completed + 1);
        update.setUpdateTime(now);
        feRegistrationBatchMapper.updateById(update);
        batch.setCompletedCount(completed + 1);
    }

    /**
     * 校验 confirmed_work_type 必须属于该订单用工明细中的工种，返回规范化后的工种名。
     */
    private String requireOrderJobType(Long orderId, String confirmedWorkType) {
        if (!StringUtils.hasText(confirmedWorkType)) {
            throw new BizException(ErrorCode.BAD_REQUEST, "confirmed_work_type 不能为空");
        }
        String workType = confirmedWorkType.trim();
        List<FeOrderWorkItem> items = orderWorkItemService.listByOrderId(orderId);
        if (items == null || items.isEmpty()) {
            throw new BizException(ErrorCode.BAD_REQUEST, "该用工订单未配置工种，无法申请加入");
        }
        for (FeOrderWorkItem item : items) {
            if (item != null && StringUtils.hasText(item.getJobType())
                    && workType.equals(item.getJobType().trim())) {
                return item.getJobType().trim();
            }
        }
        throw new BizException(ErrorCode.BAD_REQUEST, "工种不在本订单用工范围内：" + workType);
    }

    private FeRegistrationBatch requireActiveBatchByScene(String scene) {
        FeRegistrationBatch batch = feRegistrationBatchMapper.selectOne(new LambdaQueryWrapper<FeRegistrationBatch>()
                .eq(FeRegistrationBatch::getQrToken, scene)
                .orderByDesc(FeRegistrationBatch::getId)
                .last("LIMIT 1"));
        if (batch == null) {
            FeEmploymentOrder order = feEmploymentOrderMapper.selectOne(new LambdaQueryWrapper<FeEmploymentOrder>()
                    .eq(FeEmploymentOrder::getOrderNo, scene)
                    .orderByDesc(FeEmploymentOrder::getId)
                    .last("LIMIT 1"));
            if (order != null) {
                batch = feRegistrationBatchMapper.selectOne(new LambdaQueryWrapper<FeRegistrationBatch>()
                        .eq(FeRegistrationBatch::getOrderId, order.getId())
                        .orderByDesc(FeRegistrationBatch::getId)
                        .last("LIMIT 1"));
            }
        }
        if (batch == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "未找到对应用工邀请");
        }
        if (!BATCH_ACTIVE.equals(batch.getStatus())) {
            throw new BizException(ErrorCode.BAD_REQUEST, "该用工邀请已关闭或失效");
        }
        LocalDateTime now = LocalDateTime.now();
        if (batch.getValidUntil() != null && now.isAfter(batch.getValidUntil())) {
            throw new BizException(ErrorCode.BAD_REQUEST, "该用工邀请已过期");
        }
        if (batch.getValidFrom() != null && now.isBefore(batch.getValidFrom())) {
            throw new BizException(ErrorCode.BAD_REQUEST, "该用工邀请尚未生效");
        }
        return batch;
    }

    /** 批次未绑定企业时禁止申请（含禁止插入 fe_worker_registration）。 */
    private static void requireBatchEnterprise(FeRegistrationBatch batch) {
        if (batch == null || batch.getEnterpriseId() == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "该用工邀请尚未完成企业认证，暂不可申请加入");
        }
    }

    /**
     * 按订单 worker_source 判定登记记录是否第三方人力来源：
     * {@code recruit}=无临时工 → 1；其余（含 existing）→ 0。
     */
    private static int resolveThirdPartySource(FeEmploymentOrder order) {
        if (order != null && WORKER_SOURCE_RECRUIT.equalsIgnoreCase(
                order.getWorkerSource() != null ? order.getWorkerSource().trim() : null)) {
            return THIRD_PARTY_YES;
        }
        return THIRD_PARTY_NO;
    }

    private void assertBatchHasCapacity(FeRegistrationBatch batch) {
        int expected = batch.getExpectedCount() != null ? batch.getExpectedCount() : 0;
        int registered = batch.getRegisteredCount() != null ? batch.getRegisteredCount() : 0;
        if (expected > 0 && registered >= expected) {
            throw new BizException(ErrorCode.BAD_REQUEST, "该用工名额已满");
        }
    }

    private void bumpBatchCounters(FeRegistrationBatch batch, LocalDateTime now) {
        int registered = batch.getRegisteredCount() != null ? batch.getRegisteredCount() : 0;
        int pending = batch.getPendingCount() != null ? batch.getPendingCount() : 0;
        FeRegistrationBatch update = new FeRegistrationBatch();
        update.setId(batch.getId());
        update.setRegisteredCount(registered + 1);
        update.setPendingCount(Math.max(0, pending - 1));
        update.setUpdateTime(now);
        feRegistrationBatchMapper.updateById(update);
    }

    private static WorkerRegistrationApplyResponse toResponse(FeWorkerRegistration reg,
                                                              FeRegistrationBatch batch,
                                                              FeEmploymentOrder order,
                                                              String status,
                                                              String message) {
        WorkerRegistrationApplyResponse response = new WorkerRegistrationApplyResponse();
        response.setStatus(status);
        response.setRegistrationId(reg.getId());
        response.setBatchNo(batch.getBatchNo());
        response.setOrderNo(order.getOrderNo());
        response.setRegStatus(reg.getRegStatus());
        response.setThirdPartySource(reg.getThirdPartySource());
        response.setMessage(message);
        return response;
    }
}
