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

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.info.collection.domain.CcdiPurchaseTransaction;
import com.ruoyi.info.collection.domain.CcdiPurchaseTransactionSupplier;
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionAddDTO;
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionEditDTO;
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionQueryDTO;
import com.ruoyi.info.collection.domain.dto.CcdiPurchaseTransactionSupplierDTO;
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionExcel;
import com.ruoyi.info.collection.domain.excel.CcdiPurchaseTransactionSupplierExcel;
import com.ruoyi.info.collection.domain.vo.CcdiPurchaseTransactionVO;
import com.ruoyi.info.collection.domain.vo.CcdiPurchaseTransactionSupplierVO;
import com.ruoyi.info.collection.enums.DataSource;
import com.ruoyi.info.collection.enums.EnterpriseSource;
import com.ruoyi.info.collection.mapper.CcdiPurchaseTransactionMapper;
import com.ruoyi.info.collection.mapper.CcdiPurchaseTransactionSupplierMapper;
import com.ruoyi.info.collection.service.ICcdiPurchaseTransactionImportService;
import com.ruoyi.info.collection.service.ICcdiPurchaseTransactionService;
import com.ruoyi.info.collection.service.support.EnterpriseAutoFillService;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 采购交易信息 服务层处理
 *
 * @author ruoyi
 * @date 2026-02-06
 */
@Service
public class CcdiPurchaseTransactionServiceImpl implements ICcdiPurchaseTransactionService {

    @Resource
    private CcdiPurchaseTransactionMapper transactionMapper;

    @Resource
    private ICcdiPurchaseTransactionImportService transactionImportService;

    @Resource
    private CcdiPurchaseTransactionSupplierMapper supplierMapper;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private EnterpriseAutoFillService enterpriseAutoFillService;

    /**
     * 查询采购交易列表
     *
     * @param queryDTO 查询条件
     * @return 采购交易VO集合
     */
    @Override
    public java.util.List<CcdiPurchaseTransactionVO> selectTransactionList(CcdiPurchaseTransactionQueryDTO queryDTO) {
        Page<CcdiPurchaseTransactionVO> page = new Page<>(1, Integer.MAX_VALUE);
        Page<CcdiPurchaseTransactionVO> resultPage = transactionMapper.selectTransactionPage(page, queryDTO);
        return resultPage.getRecords();
    }

    /**
     * 分页查询采购交易列表
     *
     * @param page     分页对象
     * @param queryDTO 查询条件
     * @return 采购交易VO分页结果
     */
    @Override
    public Page<CcdiPurchaseTransactionVO> selectTransactionPage(Page<CcdiPurchaseTransactionVO> page, CcdiPurchaseTransactionQueryDTO queryDTO) {
        return transactionMapper.selectTransactionPage(page, queryDTO);
    }

    /**
     * 查询采购交易列表（用于导出）
     *
     * @param queryDTO 查询条件
     * @return 采购交易Excel实体集合
     */
    @Override
    public java.util.List<CcdiPurchaseTransactionExcel> selectTransactionListForExport(CcdiPurchaseTransactionQueryDTO queryDTO) {
        Page<CcdiPurchaseTransactionVO> page = new Page<>(1, Integer.MAX_VALUE);
        Page<CcdiPurchaseTransactionVO> resultPage = transactionMapper.selectTransactionPage(page, queryDTO);

        return resultPage.getRecords().stream().map(vo -> {
            CcdiPurchaseTransactionExcel excel = new CcdiPurchaseTransactionExcel();
            BeanUtils.copyProperties(vo, excel);
            return excel;
        }).collect(Collectors.toList());
    }

    /**
     * 查询采购交易详情
     *
     * @param purchaseId 采购事项ID
     * @return 采购交易VO
     */
    @Override
    public CcdiPurchaseTransactionVO selectTransactionById(String purchaseId) {
        CcdiPurchaseTransactionVO detail = transactionMapper.selectTransactionById(purchaseId);
        if (detail == null) {
            return null;
        }
        List<CcdiPurchaseTransactionSupplierVO> supplierList = selectSupplierListByPurchaseId(purchaseId);
        detail.setSupplierList(supplierList);
        detail.setSupplierCount(supplierList.size());
        return detail;
    }

    /**
     * 新增采购交易
     *
     * @param addDTO 新增DTO
     * @return 结果
     */
    @Override
    @Transactional
    public int insertTransaction(CcdiPurchaseTransactionAddDTO addDTO) {
        // 检查采购事项ID唯一性
        if (transactionMapper.selectById(addDTO.getPurchaseId()) != null) {
            throw new RuntimeException("该采购事项ID已存在");
        }

        List<CcdiPurchaseTransactionSupplier> supplierList = buildSupplierEntities(addDTO.getPurchaseId(), addDTO.getSupplierList());
        CcdiPurchaseTransaction transaction = new CcdiPurchaseTransaction();
        BeanUtils.copyProperties(addDTO, transaction);
        fillWinnerSummary(transaction, supplierList);
        autoFillSupplierEnterprises(supplierList, DataSource.MANUAL.getCode(), SecurityUtils.getUsername());
        int result = transactionMapper.insert(transaction);
        saveSuppliers(supplierList);

        return result;
    }

    /**
     * 修改采购交易
     *
     * @param editDTO 编辑DTO
     * @return 结果
     */
    @Override
    @Transactional
    public int updateTransaction(CcdiPurchaseTransactionEditDTO editDTO) {
        List<CcdiPurchaseTransactionSupplier> supplierList = buildSupplierEntities(editDTO.getPurchaseId(), editDTO.getSupplierList());
        CcdiPurchaseTransaction transaction = new CcdiPurchaseTransaction();
        BeanUtils.copyProperties(editDTO, transaction);
        fillWinnerSummary(transaction, supplierList);
        int result = transactionMapper.updateById(transaction);
        transactionMapper.deleteSuppliersByPurchaseIds(List.of(editDTO.getPurchaseId()));
        saveSuppliers(supplierList);

        return result;
    }

    /**
     * 批量删除采购交易
     *
     * @param purchaseIds 需要删除的采购事项ID
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteTransactionByIds(String[] purchaseIds) {
        transactionMapper.deleteSuppliersByPurchaseIds(List.of(purchaseIds));
        return transactionMapper.deleteBatchIds(java.util.List.of(purchaseIds));
    }

    /**
     * 导入采购交易数据（异步）
     *
     * @param mainExcelList 主信息Excel实体列表
     * @param supplierExcelList 供应商明细Excel实体列表
     * @return 任务ID
     */
    @Override
    @Transactional
    public String importTransaction(
        List<CcdiPurchaseTransactionExcel> mainExcelList,
        List<CcdiPurchaseTransactionSupplierExcel> supplierExcelList
    ) {
        if ((mainExcelList == null || mainExcelList.isEmpty()) && (supplierExcelList == null || supplierExcelList.isEmpty())) {
            throw new RuntimeException("至少需要一条数据");
        }

        // 生成任务ID
        String taskId = UUID.randomUUID().toString();
        long startTime = System.currentTimeMillis();

        // 获取当前用户名
        String userName = SecurityUtils.getUsername();

        // 初始化Redis状态
        String statusKey = "import:purchaseTransaction:" + taskId;
        Map<String, Object> statusData = new HashMap<>();
        statusData.put("taskId", taskId);
        statusData.put("status", "PROCESSING");
        statusData.put("totalCount", countImportUnits(mainExcelList, supplierExcelList));
        statusData.put("successCount", 0);
        statusData.put("failureCount", 0);
        statusData.put("progress", 0);
        statusData.put("startTime", startTime);
        statusData.put("message", "正在处理...");

        redisTemplate.opsForHash().putAll(statusKey, statusData);
        redisTemplate.expire(statusKey, 7, TimeUnit.DAYS);

        // 调用异步导入服务
        transactionImportService.importTransactionAsync(mainExcelList, supplierExcelList, taskId, userName);

        return taskId;
    }

    private int countImportUnits(
        List<CcdiPurchaseTransactionExcel> mainExcelList,
        List<CcdiPurchaseTransactionSupplierExcel> supplierExcelList
    ) {
        LinkedHashSet<String> purchaseIds = new LinkedHashSet<>();
        if (mainExcelList != null) {
            purchaseIds.addAll(
                mainExcelList.stream()
                    .map(CcdiPurchaseTransactionExcel::getPurchaseId)
                    .filter(StringUtils::isNotEmpty)
                    .collect(Collectors.toCollection(LinkedHashSet::new))
            );
        }
        if (supplierExcelList != null) {
            purchaseIds.addAll(
                supplierExcelList.stream()
                    .map(CcdiPurchaseTransactionSupplierExcel::getPurchaseId)
                    .filter(StringUtils::isNotEmpty)
                    .collect(Collectors.toCollection(LinkedHashSet::new))
            );
        }
        return purchaseIds.isEmpty() ? 0 : purchaseIds.size();
    }

    private List<CcdiPurchaseTransactionSupplier> buildSupplierEntities(
        String purchaseId,
        List<CcdiPurchaseTransactionSupplierDTO> supplierDTOList
    ) {
        List<CcdiPurchaseTransactionSupplierDTO> normalizedList = normalizeSupplierList(supplierDTOList);
        validateSupplierList(normalizedList);

        List<CcdiPurchaseTransactionSupplier> supplierList = new ArrayList<>();
        for (int i = 0; i < normalizedList.size(); i++) {
            CcdiPurchaseTransactionSupplierDTO dto = normalizedList.get(i);
            CcdiPurchaseTransactionSupplier supplier = new CcdiPurchaseTransactionSupplier();
            BeanUtils.copyProperties(dto, supplier);
            supplier.setPurchaseId(purchaseId);
            supplier.setIsBidWinner(Objects.equals(dto.getIsBidWinner(), 1) ? 1 : 0);
            supplier.setSortOrder(dto.getSortOrder() == null ? i + 1 : dto.getSortOrder());
            supplierList.add(supplier);
        }
        return supplierList;
    }

    private List<CcdiPurchaseTransactionSupplierDTO> normalizeSupplierList(
        List<CcdiPurchaseTransactionSupplierDTO> supplierDTOList
    ) {
        if (supplierDTOList == null) {
            return List.of();
        }
        return supplierDTOList.stream()
            .filter(Objects::nonNull)
            .filter(this::hasAnySupplierValue)
            .toList();
    }

    private boolean hasAnySupplierValue(CcdiPurchaseTransactionSupplierDTO supplierDTO) {
        return StringUtils.isNotEmpty(supplierDTO.getSupplierName())
            || StringUtils.isNotEmpty(supplierDTO.getSupplierUscc())
            || StringUtils.isNotEmpty(supplierDTO.getContactPerson())
            || StringUtils.isNotEmpty(supplierDTO.getContactPhone())
            || StringUtils.isNotEmpty(supplierDTO.getSupplierBankAccount())
            || supplierDTO.getIsBidWinner() != null
            || supplierDTO.getSortOrder() != null;
    }

    private void validateSupplierList(List<CcdiPurchaseTransactionSupplierDTO> supplierList) {
        long winnerCount = supplierList.stream()
            .filter(item -> Objects.equals(item.getIsBidWinner(), 1))
            .count();
        if (winnerCount > 1) {
            throw new RuntimeException("同一招投标事项仅允许维护一条中标供应商");
        }

        LinkedHashSet<String> duplicateKeys = new LinkedHashSet<>();
        for (CcdiPurchaseTransactionSupplierDTO supplier : supplierList) {
            String duplicateKey = StringUtils.trimToEmpty(supplier.getSupplierName()) + "|"
                + StringUtils.trimToEmpty(supplier.getSupplierUscc());
            if (!duplicateKeys.add(duplicateKey)) {
                throw new RuntimeException("同一招投标事项存在重复供应商，请检查供应商名称和统一信用代码");
            }
        }
    }

    private void fillWinnerSummary(
        CcdiPurchaseTransaction transaction,
        List<CcdiPurchaseTransactionSupplier> supplierList
    ) {
        CcdiPurchaseTransactionSupplier winnerSupplier = supplierList.stream()
            .filter(item -> Objects.equals(item.getIsBidWinner(), 1))
            .findFirst()
            .orElse(null);
        if (winnerSupplier == null) {
            transaction.setSupplierName(null);
            transaction.setSupplierUscc(null);
            transaction.setContactPerson(null);
            transaction.setContactPhone(null);
            transaction.setSupplierBankAccount(null);
            return;
        }
        transaction.setSupplierName(winnerSupplier.getSupplierName());
        transaction.setSupplierUscc(winnerSupplier.getSupplierUscc());
        transaction.setContactPerson(winnerSupplier.getContactPerson());
        transaction.setContactPhone(winnerSupplier.getContactPhone());
        transaction.setSupplierBankAccount(winnerSupplier.getSupplierBankAccount());
    }

    private void saveSuppliers(List<CcdiPurchaseTransactionSupplier> supplierList) {
        for (CcdiPurchaseTransactionSupplier supplier : supplierList) {
            supplierMapper.insert(supplier);
        }
    }

    private void autoFillSupplierEnterprises(List<CcdiPurchaseTransactionSupplier> supplierList,
                                             String dataSource,
                                             String userName) {
        enterpriseAutoFillService.ensureExistsBatch(supplierList.stream()
            .filter(item -> StringUtils.isNotEmpty(item.getSupplierUscc()))
            .map(item -> new EnterpriseAutoFillService.EnterpriseFillItem(
                item.getSupplierUscc(),
                item.getSupplierName(),
                EnterpriseSource.SUPPLIER.getCode(),
                dataSource,
                userName
            ))
            .toList());
    }

    private List<CcdiPurchaseTransactionSupplierVO> selectSupplierListByPurchaseId(String purchaseId) {
        return supplierMapper.selectList(
            new LambdaQueryWrapper<CcdiPurchaseTransactionSupplier>()
                .eq(CcdiPurchaseTransactionSupplier::getPurchaseId, purchaseId)
                .orderByAsc(CcdiPurchaseTransactionSupplier::getSortOrder)
                .orderByAsc(CcdiPurchaseTransactionSupplier::getId)
        ).stream().map(entity -> {
            CcdiPurchaseTransactionSupplierVO vo = new CcdiPurchaseTransactionSupplierVO();
            BeanUtils.copyProperties(entity, vo);
            return vo;
        }).collect(Collectors.toList());
    }
}
