package com.huimv.employment.service.enterprise;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.CreditCodeUtils;
import com.huimv.employment.common.util.IdCardUtils;
import com.huimv.employment.common.util.MobileUtils;
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.FeEnterpriseUser;
import com.huimv.employment.dao.entity.FeRegistrationBatch;
import com.huimv.employment.dao.entity.FeUser;
import com.huimv.employment.dao.mapper.FeEmploymentDraftMapper;
import com.huimv.employment.dao.mapper.FeEmploymentOrderMapper;
import com.huimv.employment.dao.mapper.FeEnterpriseMapper;
import com.huimv.employment.dao.mapper.FeEnterpriseUserMapper;
import com.huimv.employment.dao.mapper.FeRegistrationBatchMapper;
import com.huimv.employment.dao.mapper.FeUserMapper;
import com.huimv.employment.service.config.SecurityProperties;
import com.huimv.employment.service.enterprise.dto.EnterpriseInfoResponse;
import com.huimv.employment.service.enterprise.dto.EnterpriseRegisterRequest;
import com.huimv.employment.service.enterprise.dto.EnterpriseRegisterResponse;
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.util.ArrayList;
import java.util.List;

/**
 * 企业登记 / 认证：按信用代码 upsert 企业，绑定当前用户，认证成功后设为默认企业并回填用工数据。
 */
@Service
public class EnterpriseService {

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

    private static final String USER_TYPE_ENTERPRISE = "enterprise";
    private static final String AUTH_STATUS_VERIFIED = "verified";
    private static final String ROLE_OWNER = "owner";

    private final FeUserMapper feUserMapper;
    private final FeEnterpriseMapper feEnterpriseMapper;
    private final FeEnterpriseUserMapper feEnterpriseUserMapper;
    private final FeEmploymentDraftMapper feEmploymentDraftMapper;
    private final FeEmploymentOrderMapper feEmploymentOrderMapper;
    private final FeRegistrationBatchMapper feRegistrationBatchMapper;
    private final SecurityProperties securityProperties;

    public EnterpriseService(FeUserMapper feUserMapper,
                             FeEnterpriseMapper feEnterpriseMapper,
                             FeEnterpriseUserMapper feEnterpriseUserMapper,
                             FeEmploymentDraftMapper feEmploymentDraftMapper,
                             FeEmploymentOrderMapper feEmploymentOrderMapper,
                             FeRegistrationBatchMapper feRegistrationBatchMapper,
                             SecurityProperties securityProperties) {
        this.feUserMapper = feUserMapper;
        this.feEnterpriseMapper = feEnterpriseMapper;
        this.feEnterpriseUserMapper = feEnterpriseUserMapper;
        this.feEmploymentDraftMapper = feEmploymentDraftMapper;
        this.feEmploymentOrderMapper = feEmploymentOrderMapper;
        this.feRegistrationBatchMapper = feRegistrationBatchMapper;
        this.securityProperties = securityProperties;
    }

    public FeEnterprise findEnterpriseByUserId(Long userId) {
        FeEnterpriseUser binding = findBindingByUserId(userId);
        if (binding == null) {
            return null;
        }
        return feEnterpriseMapper.selectById(binding.getEnterpriseId());
    }

    /**
     * 按主键查询企业，不存在时抛出业务异常。
     */
    public FeEnterprise requireById(Long enterpriseId) {
        if (enterpriseId == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "enterpriseId 不能为空");
        }
        FeEnterprise enterprise = feEnterpriseMapper.selectById(enterpriseId);
        if (enterprise == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "企业不存在");
        }
        return enterprise;
    }

    public FeUser requireEnterpriseUser(Long userId) {
        FeUser user = feUserMapper.selectById(userId);
        if (user == null) {
            throw new BizException(ErrorCode.UNAUTHORIZED);
        }
        if (!USER_TYPE_ENTERPRISE.equals(user.getUserType())) {
            throw new BizException(ErrorCode.ENTERPRISE_ONLY);
        }
        return user;
    }

    /**
     * 按草稿 ID 查询已关联企业信息（含法人身份证明文、未脱敏手机号）。
     * <p>仅本人草稿可查；草稿尚未绑定 {@code enterprise_id} 时返回业务错误。</p>
     */
    public EnterpriseInfoResponse getByDraftId(Long userId, Long draftId) {
        requireEnterpriseUser(userId);
        if (draftId == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "draft_id 不能为空");
        }
        FeEmploymentDraft draft = feEmploymentDraftMapper.selectById(draftId);
        if (draft == null || draft.getUserId() == null || !draft.getUserId().equals(userId)) {
            throw new BizException(ErrorCode.NOT_FOUND, "草稿不存在");
        }
        if (draft.getEnterpriseId() == null) {
            throw new BizException(ErrorCode.BAD_REQUEST, "该草稿尚未关联企业，请先完成企业认证");
        }
        // 草稿已绑企业时，校验当前用户对该企业有绑定关系（防串数据）
        FeEnterpriseUser binding = feEnterpriseUserMapper.selectOne(new LambdaQueryWrapper<FeEnterpriseUser>()
                .eq(FeEnterpriseUser::getUserId, userId)
                .eq(FeEnterpriseUser::getEnterpriseId, draft.getEnterpriseId())
                .last("LIMIT 1"));
        if (binding == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "草稿不存在");
        }
        FeEnterprise enterprise = feEnterpriseMapper.selectById(draft.getEnterpriseId());
        if (enterprise == null) {
            throw new BizException(ErrorCode.NOT_FOUND, "企业不存在");
        }
        return toInfoResponse(draftId, enterprise);
    }

    @Transactional(rollbackFor = Exception.class)
    public EnterpriseRegisterResponse register(Long userId, EnterpriseRegisterRequest request) {
        lockEnterpriseUserForUpdate(userId);

        String creditCode = request.getCreditCode().trim().toUpperCase();
        CreditCodeUtils.validate(creditCode);
        MobileUtils.validate(request.getContactMobile());
        String legalPersonIdCard = request.getLegalPersonIdCard().trim().toUpperCase();
        IdCardUtils.validate(legalPersonIdCard);

        String aesKey = securityProperties.getMobileAesKey();
        String contactMobileEnc = AesUtils.encrypt(request.getContactMobile(), aesKey);
        String contactMobileMask = MobileUtils.mask(request.getContactMobile());
        String legalPersonIdCardEnc = AesUtils.encrypt(legalPersonIdCard, aesKey);
        String legalPersonIdCardMask = IdCardUtils.mask(legalPersonIdCard);
        LocalDateTime now = LocalDateTime.now();

        // 1) credit_code 已存在则更新，否则插入；提交即认证通过（MVP）
        FeEnterprise enterprise = upsertEnterprise(request, creditCode,
                contactMobileEnc, contactMobileMask,
                legalPersonIdCardEnc, legalPersonIdCardMask, now);

        // 2) 当前用户与企业绑定：不存在插入，存在更新
        upsertEnterpriseUserBinding(userId, enterprise.getId(), now);

        // 3) 认证成功：本次绑定设为默认，清除该用户其它默认企业
        switchDefaultEnterprise(userId, enterprise.getId(), now);

        // 4) 回填指定草稿及对应订单、登记批次企业 ID
        bindDraftEmploymentToEnterprise(userId, request.getDraftId(), enterprise.getId(), now);
        bindPendingEmploymentToEnterprise(userId, enterprise.getId(), now);

        return toRegisterResponse(enterprise);
    }

    private FeEnterprise upsertEnterprise(EnterpriseRegisterRequest request,
                                          String creditCode,
                                          String contactMobileEnc,
                                          String contactMobileMask,
                                          String legalPersonIdCardEnc,
                                          String legalPersonIdCardMask,
                                          LocalDateTime now) {
        FeEnterprise existing = feEnterpriseMapper.selectOne(new LambdaQueryWrapper<FeEnterprise>()
                .eq(FeEnterprise::getCreditCode, creditCode)
                .last("LIMIT 1"));
        if (existing != null) {
            existing.setName(request.getName().trim());
            existing.setLegalPerson(request.getLegalPerson().trim());
            existing.setLegalPersonIdCardEnc(legalPersonIdCardEnc);
            existing.setLegalPersonIdCardMask(legalPersonIdCardMask);
            existing.setRegisteredAddress(request.getRegisteredAddress().trim());
            existing.setContactName(request.getContactName().trim());
            existing.setContactMobileEnc(contactMobileEnc);
            existing.setContactMobileMask(contactMobileMask);
            existing.setAuthStatus(AUTH_STATUS_VERIFIED);
            existing.setAuthTime(now);
            existing.setUpdateTime(now);
            if (!StringUtils.hasText(existing.getEnterpriseCode())) {
                existing.setEnterpriseCode(generateEnterpriseCode(existing.getId()));
            }
            try {
                feEnterpriseMapper.updateById(existing);
            } catch (DuplicateKeyException ex) {
                throw handleEnterpriseDuplicate(ex, "update");
            }
            return existing;
        }

        FeEnterprise enterprise = new FeEnterprise();
        enterprise.setName(request.getName().trim());
        enterprise.setCreditCode(creditCode);
        enterprise.setLegalPerson(request.getLegalPerson().trim());
        enterprise.setLegalPersonIdCardEnc(legalPersonIdCardEnc);
        enterprise.setLegalPersonIdCardMask(legalPersonIdCardMask);
        enterprise.setRegisteredAddress(request.getRegisteredAddress().trim());
        enterprise.setContactName(request.getContactName().trim());
        enterprise.setContactMobileEnc(contactMobileEnc);
        enterprise.setContactMobileMask(contactMobileMask);
        enterprise.setAuthStatus(AUTH_STATUS_VERIFIED);
        enterprise.setAuthTime(now);
        enterprise.setCreateTime(now);
        enterprise.setUpdateTime(now);
        enterprise.setDelFlag(0);
        try {
            feEnterpriseMapper.insert(enterprise);
        } catch (DuplicateKeyException ex) {
            throw handleEnterpriseDuplicate(ex, "insert");
        }

        enterprise.setEnterpriseCode(generateEnterpriseCode(enterprise.getId()));
        try {
            feEnterpriseMapper.updateById(enterprise);
        } catch (DuplicateKeyException ex) {
            throw handleEnterpriseDuplicate(ex, "assign enterpriseCode");
        }
        return enterprise;
    }

    /**
     * 按 (user_id, enterprise_id) upsert 绑定关系。
     */
    private void upsertEnterpriseUserBinding(Long userId, Long enterpriseId, LocalDateTime now) {
        FeEnterpriseUser binding = feEnterpriseUserMapper.selectOne(new LambdaQueryWrapper<FeEnterpriseUser>()
                .eq(FeEnterpriseUser::getUserId, userId)
                .eq(FeEnterpriseUser::getEnterpriseId, enterpriseId)
                .last("LIMIT 1"));
        if (binding != null) {
            binding.setRole(ROLE_OWNER);
            binding.setUpdateTime(now);
            try {
                feEnterpriseUserMapper.updateById(binding);
            } catch (DuplicateKeyException ex) {
                throw handleEnterpriseDuplicate(ex, "update bind");
            }
            return;
        }

        FeEnterpriseUser created = new FeEnterpriseUser();
        created.setEnterpriseId(enterpriseId);
        created.setUserId(userId);
        created.setRole(ROLE_OWNER);
        created.setIsDefault(false);
        created.setBindTime(now);
        created.setCreateTime(now);
        created.setUpdateTime(now);
        created.setDelFlag(0);
        try {
            feEnterpriseUserMapper.insert(created);
        } catch (DuplicateKeyException ex) {
            // 并发下可能已插入，改为更新
            FeEnterpriseUser raced = feEnterpriseUserMapper.selectOne(new LambdaQueryWrapper<FeEnterpriseUser>()
                    .eq(FeEnterpriseUser::getUserId, userId)
                    .eq(FeEnterpriseUser::getEnterpriseId, enterpriseId)
                    .last("LIMIT 1"));
            if (raced == null) {
                throw handleEnterpriseDuplicate(ex, "bind user");
            }
            raced.setRole(ROLE_OWNER);
            raced.setUpdateTime(now);
            feEnterpriseUserMapper.updateById(raced);
        }
    }

    /**
     * 将指定企业设为用户默认企业，并取消该用户其它默认。
     */
    private void switchDefaultEnterprise(Long userId, Long enterpriseId, LocalDateTime now) {
        feEnterpriseUserMapper.update(null, new LambdaUpdateWrapper<FeEnterpriseUser>()
                .eq(FeEnterpriseUser::getUserId, userId)
                .eq(FeEnterpriseUser::getIsDefault, true)
                .ne(FeEnterpriseUser::getEnterpriseId, enterpriseId)
                .set(FeEnterpriseUser::getIsDefault, false)
                .set(FeEnterpriseUser::getUpdateTime, now));

        feEnterpriseUserMapper.update(null, new LambdaUpdateWrapper<FeEnterpriseUser>()
                .eq(FeEnterpriseUser::getUserId, userId)
                .eq(FeEnterpriseUser::getEnterpriseId, enterpriseId)
                .set(FeEnterpriseUser::getIsDefault, true)
                .set(FeEnterpriseUser::getUpdateTime, now));
    }

    private void bindDraftEmploymentToEnterprise(Long userId, Long draftId, Long enterpriseId, LocalDateTime now) {
        FeEmploymentDraft draft = feEmploymentDraftMapper.selectById(draftId);
        if (draft == null || draft.getUserId() == null || !draft.getUserId().equals(userId)) {
            throw new BizException(ErrorCode.NOT_FOUND, "草稿不存在");
        }
        feEmploymentDraftMapper.update(null, new LambdaUpdateWrapper<FeEmploymentDraft>()
                .eq(FeEmploymentDraft::getId, draftId)
                .eq(FeEmploymentDraft::getUserId, userId)
                .set(FeEmploymentDraft::getEnterpriseId, enterpriseId)
                .set(FeEmploymentDraft::getUpdateTime, now));

        List<FeEmploymentOrder> orders = feEmploymentOrderMapper.selectList(
                new LambdaQueryWrapper<FeEmploymentOrder>()
                        .eq(FeEmploymentOrder::getDraftId, draftId)
                        .eq(FeEmploymentOrder::getUserId, userId)
                        .select(FeEmploymentOrder::getId));
        feEmploymentOrderMapper.update(null, new LambdaUpdateWrapper<FeEmploymentOrder>()
                .eq(FeEmploymentOrder::getDraftId, draftId)
                .eq(FeEmploymentOrder::getUserId, userId)
                .set(FeEmploymentOrder::getEnterpriseId, enterpriseId)
                .set(FeEmploymentOrder::getUpdateTime, now));

        List<Long> orderIds = collectOrderIds(orders);
        if (!orderIds.isEmpty()) {
            feRegistrationBatchMapper.update(null, new LambdaUpdateWrapper<FeRegistrationBatch>()
                    .in(FeRegistrationBatch::getOrderId, orderIds)
                    .set(FeRegistrationBatch::getEnterpriseId, enterpriseId)
                    .set(FeRegistrationBatch::getUpdateTime, now));
        }
    }

    /**
     * 将当前用户 enterprise_id 为空的草稿、订单及对应登记批次回填为企业 ID。
     */
    private void bindPendingEmploymentToEnterprise(Long userId, Long enterpriseId, LocalDateTime now) {
        if (userId == null || enterpriseId == null) {
            return;
        }
        feEmploymentDraftMapper.update(null, new LambdaUpdateWrapper<FeEmploymentDraft>()
                .eq(FeEmploymentDraft::getUserId, userId)
                .isNull(FeEmploymentDraft::getEnterpriseId)
                .set(FeEmploymentDraft::getEnterpriseId, enterpriseId)
                .set(FeEmploymentDraft::getUpdateTime, now));

        List<FeEmploymentOrder> unboundOrders = feEmploymentOrderMapper.selectList(
                new LambdaQueryWrapper<FeEmploymentOrder>()
                        .eq(FeEmploymentOrder::getUserId, userId)
                        .isNull(FeEmploymentOrder::getEnterpriseId)
                        .select(FeEmploymentOrder::getId));
        feEmploymentOrderMapper.update(null, new LambdaUpdateWrapper<FeEmploymentOrder>()
                .eq(FeEmploymentOrder::getUserId, userId)
                .isNull(FeEmploymentOrder::getEnterpriseId)
                .set(FeEmploymentOrder::getEnterpriseId, enterpriseId)
                .set(FeEmploymentOrder::getUpdateTime, now));

        List<Long> orderIds = collectOrderIds(unboundOrders);
        if (!orderIds.isEmpty()) {
            feRegistrationBatchMapper.update(null, new LambdaUpdateWrapper<FeRegistrationBatch>()
                    .in(FeRegistrationBatch::getOrderId, orderIds)
                    .isNull(FeRegistrationBatch::getEnterpriseId)
                    .set(FeRegistrationBatch::getEnterpriseId, enterpriseId)
                    .set(FeRegistrationBatch::getUpdateTime, now));
        }
    }

    private static List<Long> collectOrderIds(List<FeEmploymentOrder> orders) {
        List<Long> orderIds = new ArrayList<>();
        if (orders == null) {
            return orderIds;
        }
        for (FeEmploymentOrder order : orders) {
            if (order != null && order.getId() != null) {
                orderIds.add(order.getId());
            }
        }
        return orderIds;
    }

    /**
     * 事务内锁定 fe_user 行，串行化同一用户的并发登记请求。
     */
    private FeUser lockEnterpriseUserForUpdate(Long userId) {
        FeUser user = feUserMapper.selectByIdForUpdate(userId);
        if (user == null) {
            throw new BizException(ErrorCode.UNAUTHORIZED);
        }
        if (!USER_TYPE_ENTERPRISE.equals(user.getUserType())) {
            throw new BizException(ErrorCode.ENTERPRISE_ONLY);
        }
        return user;
    }

    private BizException handleEnterpriseDuplicate(DuplicateKeyException ex, String phase) {
        String message = ex.getMessage();
        if (message != null && (message.contains("uk_fe_enterprise_credit_code") || message.contains("credit_code"))) {
            return new BizException(ErrorCode.BAD_REQUEST, "该统一社会信用代码已被登记");
        }
        if (message != null && (message.contains("uk_fe_enterprise_code") || message.contains("enterprise_code"))) {
            log.error("Duplicate enterprise_code during {}, should not happen", phase, ex);
            return new BizException(ErrorCode.INTERNAL_ERROR);
        }
        if (message != null && message.contains("uk_fe_enterprise_user")) {
            return new BizException(ErrorCode.BAD_REQUEST, "企业用户绑定冲突，请重试");
        }
        log.warn("Unexpected duplicate key during enterprise register {}: {}", phase, message);
        return new BizException(ErrorCode.INTERNAL_ERROR);
    }

    private FeEnterpriseUser findBindingByUserId(Long userId) {
        // 仅取默认企业（is_default=1）；无默认则返回空
        return feEnterpriseUserMapper.selectOne(new LambdaQueryWrapper<FeEnterpriseUser>()
                .eq(FeEnterpriseUser::getUserId, userId)
                .eq(FeEnterpriseUser::getIsDefault, true)
                .last("LIMIT 1"));
    }

    private static String generateEnterpriseCode(Long enterpriseId) {
        return String.format("ENT%d%06d", LocalDateTime.now().getYear(), enterpriseId);
    }

    private static EnterpriseRegisterResponse toRegisterResponse(FeEnterprise enterprise) {
        EnterpriseRegisterResponse response = new EnterpriseRegisterResponse();
        response.setEnterpriseId(enterprise.getId());
        response.setEnterpriseCode(enterprise.getEnterpriseCode());
        response.setName(enterprise.getName());
        response.setCreditCode(enterprise.getCreditCode());
        response.setLegalPerson(enterprise.getLegalPerson());
        response.setRegisteredAddress(enterprise.getRegisteredAddress());
        response.setContactName(enterprise.getContactName());
        response.setContactMobileMask(enterprise.getContactMobileMask());
        response.setAuthStatus(enterprise.getAuthStatus());
        return response;
    }

    private EnterpriseInfoResponse toInfoResponse(Long draftId, FeEnterprise enterprise) {
        EnterpriseInfoResponse response = new EnterpriseInfoResponse();
        response.setDraftId(draftId);
        response.setEnterpriseId(enterprise.getId());
        response.setEnterpriseCode(enterprise.getEnterpriseCode());
        response.setName(enterprise.getName());
        response.setCreditCode(enterprise.getCreditCode());
        response.setLegalPerson(enterprise.getLegalPerson());
        response.setLegalPersonIdCardMask(enterprise.getLegalPersonIdCardMask());
        response.setLegalPersonIdCard(decryptQuietly(enterprise.getLegalPersonIdCardEnc()));
        response.setRegisteredAddress(enterprise.getRegisteredAddress());
        response.setContactName(enterprise.getContactName());
        response.setContactMobileMask(enterprise.getContactMobileMask());
        response.setContactMobile(decryptQuietly(enterprise.getContactMobileEnc()));
        response.setAuthStatus(enterprise.getAuthStatus());
        return response;
    }

    private String decryptQuietly(String cipherText) {
        if (!StringUtils.hasText(cipherText)) {
            return null;
        }
        try {
            return AesUtils.decrypt(cipherText, securityProperties.getMobileAesKey());
        } catch (Exception ex) {
            log.warn("敏感字段解密失败，跳过明文回显：{}", ex.getMessage());
            return null;
        }
    }
}
