package com.ruoyi.info.collection.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.info.collection.domain.CcdiBaseStaff;
import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffAddDTO;
import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffEditDTO;
import com.ruoyi.info.collection.domain.dto.CcdiBaseStaffQueryDTO;
import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffAssetInfoExcel;
import com.ruoyi.info.collection.domain.excel.CcdiBaseStaffExcel;
import com.ruoyi.info.collection.domain.vo.BaseStaffImportSubmitResultVO;
import com.ruoyi.info.collection.domain.vo.CcdiAssetInfoVO;
import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffOptionVO;
import com.ruoyi.info.collection.domain.vo.CcdiBaseStaffVO;
import com.ruoyi.info.collection.enums.EmployeeStatus;
import com.ruoyi.info.collection.mapper.CcdiBaseStaffMapper;
import com.ruoyi.info.collection.service.ICcdiAssetInfoService;
import com.ruoyi.info.collection.service.ICcdiBaseStaffAssetImportService;
import com.ruoyi.info.collection.service.ICcdiBaseStaffImportService;
import com.ruoyi.info.collection.service.ICcdiBaseStaffService;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * 员工信息 服务层处理
 *
 * @author ruoyi
 * @date 2026-01-28
 */
@Service
public class CcdiBaseStaffServiceImpl implements ICcdiBaseStaffService {

    @Resource
    private CcdiBaseStaffMapper baseStaffMapper;

    @Resource
    private ICcdiBaseStaffImportService importAsyncService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private ICcdiAssetInfoService assetInfoService;

    @Resource
    private ICcdiBaseStaffAssetImportService baseStaffAssetImportService;

    @Resource
    private CcdiDualSheetImportOrchestrationService dualSheetImportOrchestrationService;

    /**
     * 查询员工列表
     *
     * @param queryDTO 查询条件
     * @return 员工VO集合
     */
    @Override
    public List<CcdiBaseStaffVO> selectBaseStaffList(CcdiBaseStaffQueryDTO queryDTO) {
        LambdaQueryWrapper<CcdiBaseStaff> wrapper = buildQueryWrapper(queryDTO);
        List<CcdiBaseStaff> list = baseStaffMapper.selectList(wrapper);
        List<CcdiBaseStaffVO> voList = new ArrayList<>();
        for (CcdiBaseStaff staff : list) {
            voList.add(convertToVO(staff));
        }
        return voList;
    }

    /**
     * 分页查询员工列表
     *
     * @param page     分页对象
     * @param queryDTO 查询条件
     * @return 员工VO分页结果
     */
    @Override
    public Page<CcdiBaseStaffVO> selectBaseStaffPage(Page<CcdiBaseStaffVO> page, CcdiBaseStaffQueryDTO queryDTO) {
        // 使用关联查询获取部门名称
        Page<CcdiBaseStaffVO> voPage = new Page<>(page.getCurrent(), page.getSize());
        Page<CcdiBaseStaffVO> resultPage = baseStaffMapper.selectBaseStaffPageWithDept(voPage, queryDTO);

        // 设置状态描述
        resultPage.getRecords().forEach(vo ->
            vo.setStatusDesc(EmployeeStatus.getDescByCode(vo.getStatus()))
        );

        return resultPage;
    }

    /**
     * 查询员工列表（用于导出）
     *
     * @param queryDTO 查询条件
     * @return 员工Excel实体集合
     */
    @Override
    public List<CcdiBaseStaffExcel> selectBaseStaffListForExport(CcdiBaseStaffQueryDTO queryDTO) {
        LambdaQueryWrapper<CcdiBaseStaff> wrapper = buildQueryWrapper(queryDTO);
        List<CcdiBaseStaff> list = baseStaffMapper.selectList(wrapper);
        return list.stream().map(staff -> {
            CcdiBaseStaffExcel excel = new CcdiBaseStaffExcel();
            BeanUtils.copyProperties(staff, excel);
            return excel;
        }).toList();
    }

    /**
     * 查询员工详情
     *
     * @param staffId 员工ID
     * @return 员工VO
     */
    @Override
    public CcdiBaseStaffVO selectBaseStaffById(Long staffId) {
        CcdiBaseStaffVO vo = baseStaffMapper.selectBaseStaffByIdWithDept(staffId);
        if (vo != null) {
            vo.setStatusDesc(EmployeeStatus.getDescByCode(vo.getStatus()));
            vo.setAssetInfoList(assetInfoService.selectByFamilyIdAndPersonId(vo.getIdCard(), vo.getIdCard()).stream().map(asset -> {
                CcdiAssetInfoVO assetInfoVO = new CcdiAssetInfoVO();
                BeanUtils.copyProperties(asset, assetInfoVO);
                return assetInfoVO;
            }).toList());
        }
        return vo;
    }

    /**
     * 新增员工
     *
     * @param addDTO 新增DTO
     * @return 结果
     */
    @Override
    @Transactional
    public int insertBaseStaff(CcdiBaseStaffAddDTO addDTO) {
        validateAnnualIncome(addDTO.getAnnualIncome(), "年收入");
        validatePartyMember(addDTO.getPartyMember(), "是否党员");
        // 检查员工ID唯一性
        if (baseStaffMapper.selectById(addDTO.getStaffId()) != null) {
            throw new RuntimeException("该员工ID已存在");
        }

        // 检查身份证号唯一性
        LambdaQueryWrapper<CcdiBaseStaff> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CcdiBaseStaff::getIdCard, addDTO.getIdCard());
        if (baseStaffMapper.selectCount(wrapper) > 0) {
            throw new RuntimeException("该身份证号已存在");
        }

        CcdiBaseStaff staff = new CcdiBaseStaff();
        BeanUtils.copyProperties(addDTO, staff);
        int result = baseStaffMapper.insert(staff);
        assetInfoService.replaceByFamilyId(addDTO.getIdCard(), addDTO.getAssetInfoList());

        return result;
    }

    /**
     * 修改员工
     *
     * @param editDTO 编辑DTO
     * @return 结果
     */
    @Override
    @Transactional
    public int updateBaseStaff(CcdiBaseStaffEditDTO editDTO) {
        validateAnnualIncome(editDTO.getAnnualIncome(), "年收入");
        validatePartyMember(editDTO.getPartyMember(), "是否党员");
        CcdiBaseStaff existing = baseStaffMapper.selectById(editDTO.getStaffId());
        if (existing == null) {
            throw new RuntimeException("员工不存在");
        }

        // 检查身份证号唯一性（排除自己）
        if (StringUtils.isNotEmpty(editDTO.getIdCard())) {
            LambdaQueryWrapper<CcdiBaseStaff> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(CcdiBaseStaff::getIdCard, editDTO.getIdCard())
                    .ne(CcdiBaseStaff::getStaffId, editDTO.getStaffId());
            if (baseStaffMapper.selectCount(wrapper) > 0) {
                throw new RuntimeException("该身份证号已存在");
            }
        }

        CcdiBaseStaff staff = new CcdiBaseStaff();
        BeanUtils.copyProperties(editDTO, staff);
        int result = baseStaffMapper.updateById(staff);

        if (!StringUtils.equals(existing.getIdCard(), editDTO.getIdCard())) {
            assetInfoService.deleteByFamilyId(existing.getIdCard());
        }
        assetInfoService.replaceByFamilyId(editDTO.getIdCard(), editDTO.getAssetInfoList());

        return result;
    }

    /**
     * 批量删除员工
     *
     * @param staffIds 需要删除的员工ID
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteBaseStaffByIds(Long[] staffIds) {
        List<Long> idList = List.of(staffIds);
        List<String> familyIds = baseStaffMapper.selectBatchIds(idList).stream()
                .map(CcdiBaseStaff::getIdCard)
                .filter(StringUtils::isNotEmpty)
                .toList();
        assetInfoService.deleteByFamilyIds(familyIds);
        return baseStaffMapper.deleteBatchIds(idList);
    }

    /**
     * 导入员工数据
     *
     * @param excelList Excel实体列表
     * @return 结果
     */
    @Override
    @Transactional
    public String importBaseStaff(List<CcdiBaseStaffExcel> excelList) {
        String taskId = UUID.randomUUID().toString();
        initializeImportStatus("import:baseStaff:", taskId, excelList.size());

        importAsyncService.importBaseStaffAsync(excelList, taskId);

        return taskId;
    }

    @Override
    @Transactional
    public BaseStaffImportSubmitResultVO importBaseStaffWithAssets(List<CcdiBaseStaffExcel> staffList,
                                                                   List<CcdiBaseStaffAssetInfoExcel> assetList) {
        boolean hasStaffRows = staffList != null && !staffList.isEmpty();
        boolean hasAssetRows = assetList != null && !assetList.isEmpty();
        if (!hasStaffRows && !hasAssetRows) {
            throw new RuntimeException("至少需要一条数据");
        }

        BaseStaffImportSubmitResultVO result = new BaseStaffImportSubmitResultVO();
        result.setMessage(buildImportSubmitMessage(hasStaffRows, hasAssetRows));

        if (hasStaffRows && !hasAssetRows) {
            result.setStaffTaskId(importBaseStaff(staffList));
            return result;
        }
        if (!hasStaffRows) {
            result.setAssetTaskId(baseStaffAssetImportService.importAssetInfo(assetList));
            return result;
        }

        String staffTaskId = UUID.randomUUID().toString();
        String assetTaskId = UUID.randomUUID().toString();
        initializeImportStatus("import:baseStaff:", staffTaskId, staffList.size());
        initializeImportStatus("import:baseStaffAsset:", assetTaskId, assetList.size());

        result.setStaffTaskId(staffTaskId);
        result.setAssetTaskId(assetTaskId);
        dualSheetImportOrchestrationService.importBaseStaffWithAssetsAsync(
                staffList,
                staffTaskId,
                assetList,
                assetTaskId,
                currentUserName()
        );
        return result;
    }

    /**
     * 查询员工下拉列表
     * 支持按员工ID或姓名模糊搜索，只返回在职员工
     *
     * @param query 搜索关键词(员工ID或姓名)
     * @return 员工选项列表
     */
    @Override
    public List<CcdiBaseStaffOptionVO> selectStaffOptions(String query) {
        return baseStaffMapper.selectStaffOptions(query);
    }

    private void initializeImportStatus(String keyPrefix, String taskId, int totalCount) {
        Map<String, Object> statusData = new HashMap<>();
        statusData.put("taskId", taskId);
        statusData.put("status", "PROCESSING");
        statusData.put("totalCount", totalCount);
        statusData.put("successCount", 0);
        statusData.put("failureCount", 0);
        statusData.put("progress", 0);
        statusData.put("startTime", System.currentTimeMillis());
        statusData.put("message", "正在处理...");

        String statusKey = keyPrefix + taskId;
        redisTemplate.opsForHash().putAll(statusKey, statusData);
        redisTemplate.expire(statusKey, 7, java.util.concurrent.TimeUnit.DAYS);
    }

    private String buildImportSubmitMessage(boolean hasStaffRows, boolean hasAssetRows) {
        if (hasStaffRows && hasAssetRows) {
            return "已提交员工信息和员工资产信息导入任务";
        }
        if (hasStaffRows) {
            return "已提交员工信息导入任务";
        }
        return "已提交员工资产信息导入任务";
    }

    private String currentUserName() {
        try {
            return SecurityUtils.getUsername();
        } catch (Exception e) {
            return "system";
        }
    }

    /**
     * 构建查询条件
     */
    private LambdaQueryWrapper<CcdiBaseStaff> buildQueryWrapper(CcdiBaseStaffQueryDTO queryDTO) {
        LambdaQueryWrapper<CcdiBaseStaff> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotEmpty(queryDTO.getName()), CcdiBaseStaff::getName, queryDTO.getName())
                .eq(queryDTO.getStaffId() != null, CcdiBaseStaff::getStaffId, queryDTO.getStaffId())
                .eq(queryDTO.getDeptId() != null, CcdiBaseStaff::getDeptId, queryDTO.getDeptId())
                .like(StringUtils.isNotEmpty(queryDTO.getIdCard()), CcdiBaseStaff::getIdCard, queryDTO.getIdCard())
                .eq(StringUtils.isNotEmpty(queryDTO.getStatus()), CcdiBaseStaff::getStatus, queryDTO.getStatus())
                .orderByDesc(CcdiBaseStaff::getCreateTime);
        return wrapper;
    }

    /**
     * 转换为VO对象
     */
    public CcdiBaseStaffVO convertToVO(CcdiBaseStaff staff) {
        if (staff == null) {
            return null;
        }

        CcdiBaseStaffVO vo = new CcdiBaseStaffVO();
        BeanUtils.copyProperties(staff, vo);
        vo.setStatusDesc(EmployeeStatus.getDescByCode(staff.getStatus()));
        return vo;
    }

    private void validateAnnualIncome(BigDecimal annualIncome, String fieldLabel) {
        if (annualIncome == null) {
            return;
        }
        if (annualIncome.compareTo(BigDecimal.ZERO) < 0) {
            throw new RuntimeException(fieldLabel + "不能为负数");
        }
        if (annualIncome.scale() > 2) {
            throw new RuntimeException(fieldLabel + "最多保留2位小数");
        }
    }

    private void validatePartyMember(Integer partyMember, String fieldLabel) {
        if (partyMember == null) {
            throw new RuntimeException(fieldLabel + "不能为空");
        }
        if (partyMember != 0 && partyMember != 1) {
            throw new RuntimeException(fieldLabel + "只能填写'0'或'1'");
        }
    }

}
