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.dao.entity.FeEmploymentOrder;
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.mapper.FeEmploymentOrderMapper;
import com.huimv.employment.dao.mapper.FeRegistrationBatchMapper;
import com.huimv.employment.dao.mapper.FeWorkerRegistrationMapper;
import com.huimv.employment.service.registration.dto.WorkerRegistrationApplyRequest;
import com.huimv.employment.service.registration.dto.WorkerRegistrationApplyResponse;
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;

/**
 * 用工邀请 / 批次登记：临时工扫码后申请加入。
 */
@Service
public class WorkerRegistrationService {

    private static final String BATCH_ACTIVE = "active";
    private static final String REG_UNDER_REVIEW = "under_review";
    private static final String APPLY_SUCCESS = "success";
    private static final String APPLY_ALREADY = "already_applied";

    private final FeRegistrationBatchMapper feRegistrationBatchMapper;
    private final FeEmploymentOrderMapper feEmploymentOrderMapper;
    private final FeWorkerRegistrationMapper feWorkerRegistrationMapper;
    private final WorkerService workerService;

    public WorkerRegistrationService(FeRegistrationBatchMapper feRegistrationBatchMapper,
                                     FeEmploymentOrderMapper feEmploymentOrderMapper,
                                     FeWorkerRegistrationMapper feWorkerRegistrationMapper,
                                     WorkerService workerService) {
        this.feRegistrationBatchMapper = feRegistrationBatchMapper;
        this.feEmploymentOrderMapper = feEmploymentOrderMapper;
        this.feWorkerRegistrationMapper = feWorkerRegistrationMapper;
        this.workerService = workerService;
    }

    /**
     * 临时工申请加入用工邀请（scene = 订单编号）。
     * <p>要求已完成档案登记（{@code fe_worker}）。同一批次重复申请返回已有记录。</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);
        FeEmploymentOrder order = feEmploymentOrderMapper.selectById(batch.getOrderId());
        if (order == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "用工订单不存在");
        }

        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) {
            return toResponse(existing, batch, order, APPLY_ALREADY, "您已申请加入该用工，请等待企业确认");
        }

        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());
        if (StringUtils.hasText(request.getConfirmedWorkType())) {
            reg.setConfirmedWorkType(request.getConfirmedWorkType().trim());
        } else if (StringUtils.hasText(order.getWorkType())) {
            reg.setConfirmedWorkType(order.getWorkType());
        }
        reg.setRegStatus(REG_UNDER_REVIEW);
        reg.setSubmittedAt(now);
        reg.setRemindCount(0);
        reg.setCreateTime(now);
        reg.setUpdateTime(now);
        reg.setDelFlag(0);
        feWorkerRegistrationMapper.insert(reg);

        bumpBatchCounters(batch, now);
        bumpOrderCounters(order, now);

        return toResponse(reg, batch, order, APPLY_SUCCESS, "申请已提交，请等待企业确认");
    }

    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;
    }

    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 void bumpOrderCounters(FeEmploymentOrder order, LocalDateTime now) {
        int registered = order.getRegisteredCount() != null ? order.getRegisteredCount() : 0;
        int pending = order.getPendingCount() != null ? order.getPendingCount() : 0;
        FeEmploymentOrder update = new FeEmploymentOrder();
        update.setId(order.getId());
        update.setRegisteredCount(registered + 1);
        update.setPendingCount(Math.max(0, pending - 1));
        update.setUpdateTime(now);
        feEmploymentOrderMapper.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.setMessage(message);
        return response;
    }
}
