package com.zt.plat.module.base.service.unitConversion;

import cn.hutool.core.collection.CollUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import com.zt.plat.module.base.controller.admin.unitConversion.vo.*;
import com.zt.plat.module.base.dal.dataobject.unitConversion.UnitConversionDO;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;

import com.zt.plat.module.base.dal.dao.unitConversion.UnitConversionMapper;
import com.zt.plat.module.base.dal.dao.quantityUnitRelation.QuantityUnitRelationMapper;
import com.zt.plat.module.base.dal.dao.untInfo.UntInfoMapper;
import com.zt.plat.module.base.dal.dataobject.quantityUnitRelation.QuantityUnitRelationDO;
import com.zt.plat.module.base.dal.dataobject.untInfo.UntInfoDO;
import com.zt.plat.module.base.dal.dataobject.unitQuantity.UnitQuantityDO;
import com.zt.plat.module.base.service.unitQuantity.UnitQuantityService;
import com.zt.plat.module.base.util.UnitConversionUtil;
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.stream.Collectors;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.framework.common.util.collection.CollectionUtils.convertList;
import static com.zt.plat.module.unitmanagement.enums.UnitErrorCodeConstants.*;

/**
 * 单位转换 Service 实现类
 *
 * @author 后台管理-1
 */
@Service
@Validated
@Slf4j
public class UnitConversionServiceImpl implements UnitConversionService {

    @Resource
    private UnitConversionMapper unitConversionMapper;

    @Resource
    private QuantityUnitRelationMapper quantityUnitRelationMapper;

    @Resource
    private UntInfoMapper untInfoMapper;

    @Resource
    private UnitQuantityService unitQuantityService;

    @Override
    public UnitConversionRespVO createUnitConversion(UnitConversionSaveReqVO createReqVO) {
        // 插入
        UnitConversionDO unitConversion = BeanUtils.toBean(createReqVO, UnitConversionDO.class);
        unitConversionMapper.insert(unitConversion);
        // 返回
        return BeanUtils.toBean(unitConversion, UnitConversionRespVO.class);
    }

    @Override
    public void updateUnitConversion(UnitConversionSaveReqVO updateReqVO) {
        // 校验存在
        validateUnitConversionExists(updateReqVO.getId());
        // 更新
        UnitConversionDO updateObj = BeanUtils.toBean(updateReqVO, UnitConversionDO.class);
        unitConversionMapper.updateById(updateObj);
    }

    @Override
    public void deleteUnitConversion(Long id) {
        // 校验存在
        validateUnitConversionExists(id);
        // 删除
        unitConversionMapper.deleteById(id);
    }

    @Override
        public void deleteUnitConversionListByIds(List<Long> ids) {
        // 校验存在
        validateUnitConversionExists(ids);
        // 删除
        unitConversionMapper.deleteByIds(ids);
        }

    private void validateUnitConversionExists(List<Long> ids) {
        List<UnitConversionDO> list = unitConversionMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(UNIT_CONVERSION_NOT_EXISTS);
        }
    }

    private void validateUnitConversionExists(Long id) {
        if (unitConversionMapper.selectById(id) == null) {
            throw exception(UNIT_CONVERSION_NOT_EXISTS);
        }
    }

    @Override
    public UnitConversionDO getUnitConversion(Long id) {
        return unitConversionMapper.selectById(id);
    }

    @Override
    public PageResult<UnitConversionDO> getUnitConversionPage(UnitConversionPageReqVO pageReqVO) {
        return unitConversionMapper.selectPage(pageReqVO);
    }

    @Override
    public UnitConvertRespVO convert(UnitConvertReqVO convertReqVO) {
        log.info("开始单位转换: 源单位ID={}, 目标单位ID={}, 值={}",
                convertReqVO.getSrcUntId(), convertReqVO.getTgtUntId(), convertReqVO.getValue());

        // 1. 查询所有转换规则和关联关系
        List<UnitConversionDO> conversions = unitConversionMapper.selectList();
        List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();

        // 2. 使用工具类进行转换
        UnitConversionUtil.ConversionResult result = UnitConversionUtil.convert(
                convertReqVO.getValue(),
                convertReqVO.getSrcUntId(),
                convertReqVO.getTgtUntId(),
                conversions,
                relations,
                convertReqVO.getPrecision() != null ? convertReqVO.getPrecision() : 6
        );

        // 3. 查询单位信息
        UntInfoDO srcUnit = untInfoMapper.selectById(convertReqVO.getSrcUntId());
        UntInfoDO tgtUnit = untInfoMapper.selectById(convertReqVO.getTgtUntId());

        // 4. 构建响应
        return UnitConvertRespVO.builder()
                .srcUntId(convertReqVO.getSrcUntId())
                .srcUntName(srcUnit != null ? srcUnit.getName() : null)
                .srcUntSmb(srcUnit != null ? srcUnit.getSmb() : null)
                .tgtUntId(convertReqVO.getTgtUntId())
                .tgtUntName(tgtUnit != null ? tgtUnit.getName() : null)
                .tgtUntSmb(tgtUnit != null ? tgtUnit.getSmb() : null)
                .originalValue(convertReqVO.getValue())
                .convertedValue(result.getValue())
                .factor(result.getFactor())
                .formula(result.getFormula())
                .strategy(result.getStrategy().name())
                .build();
    }

    @Override
    public BatchUnitConvertRespVO batchConvert(BatchUnitConvertReqVO batchReqVO) {
        log.info("开始批量单位转换: 转换项数量={}, 忽略错误={}",
                batchReqVO.getItems().size(), batchReqVO.getIgnoreErrors());

        List<BatchUnitConvertRespVO.UnitConvertResultItem> results = new ArrayList<>();
        int successCount = 0;
        int failureCount = 0;

        for (UnitConvertReqVO item : batchReqVO.getItems()) {
            try {
                // 执行转换
                UnitConvertRespVO convertResult = convert(item);

                // 构建成功结果
                results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
                        .success(true)
                        .data(convertResult)
                        .request(item)
                        .build());

                successCount++;
            } catch (Exception e) {
                log.warn("单位转换失败: 源单位ID={}, 目标单位ID={}, 错误={}",
                        item.getSrcUntId(), item.getTgtUntId(), e.getMessage());

                // 构建失败结果
                results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
                        .success(false)
                        .errorMessage(e.getMessage())
                        .request(item)
                        .build());

                failureCount++;

                // 如果不忽略错误，直接抛出异常
                if (!Boolean.TRUE.equals(batchReqVO.getIgnoreErrors())) {
                    throw e;
                }
            }
        }

        return BatchUnitConvertRespVO.builder()
                .results(results)
                .successCount(successCount)
                .failureCount(failureCount)
                .totalCount(batchReqVO.getItems().size())
                .build();
    }

    @Override
    public UnitConvertRespVO convertBySymbol(UnitConvertBySymbolReqVO reqVO) {
        log.info("开始按符号转换: 源单位符号={}, 目标单位符号={}, 值={}",
                reqVO.getSrcUnitSymbol(), reqVO.getTgtUnitSymbol(), reqVO.getValue());

        // 1. 查询所有转换规则、关联关系和单位信息
        List<UnitConversionDO> conversions = unitConversionMapper.selectList();
        List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
        List<UntInfoDO> units = untInfoMapper.selectList();

        // 2. 使用工具类进行转换
        UnitConversionUtil.ConversionResult result = UnitConversionUtil.convertBySymbol(
                reqVO.getValue(),
                reqVO.getSrcUnitSymbol(),
                reqVO.getTgtUnitSymbol(),
                conversions,
                relations,
                units,
                reqVO.getPrecision() != null ? reqVO.getPrecision() : 6
        );

        // 3. 构建响应
        return UnitConvertRespVO.builder()
                .srcUntName(reqVO.getSrcUnitSymbol())
                .srcUntSmb(reqVO.getSrcUnitSymbol())
                .tgtUntName(reqVO.getTgtUnitSymbol())
                .tgtUntSmb(reqVO.getTgtUnitSymbol())
                .originalValue(reqVO.getValue())
                .convertedValue(result.getValue())
                .factor(result.getFactor())
                .formula(result.getFormula())
                .strategy(result.getStrategy().name())
                .build();
    }

    @Override
    public UnitConvertRespVO convertByName(UnitConvertByNameReqVO reqVO) {
        log.info("开始按名称转换: 源单位名称={}, 目标单位名称={}, 值={}",
                reqVO.getSrcUnitName(), reqVO.getTgtUnitName(), reqVO.getValue());

        // 1. 查询所有转换规则、关联关系和单位信息
        List<UnitConversionDO> conversions = unitConversionMapper.selectList();
        List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
        List<UntInfoDO> units = untInfoMapper.selectList();

        // 2. 使用工具类进行转换
        UnitConversionUtil.ConversionResult result = UnitConversionUtil.convertByName(
                reqVO.getValue(),
                reqVO.getSrcUnitName(),
                reqVO.getTgtUnitName(),
                conversions,
                relations,
                units,
                reqVO.getPrecision() != null ? reqVO.getPrecision() : 6
        );

        // 3. 构建响应
        return UnitConvertRespVO.builder()
                .srcUntName(reqVO.getSrcUnitName())
                .tgtUntName(reqVO.getTgtUnitName())
                .originalValue(reqVO.getValue())
                .convertedValue(result.getValue())
                .factor(result.getFactor())
                .formula(result.getFormula())
                .strategy(result.getStrategy().name())
                .build();
    }

    @Override
    public BatchUnitConvertRespVO batchConvertBySymbol(BatchUnitConvertBySymbolReqVO reqVO) {
        log.info("开始批量按符号转换: 源单位符号={}, 目标单位符号={}, 值数量={}",
                reqVO.getSrcUnitSymbol(), reqVO.getTgtUnitSymbol(), reqVO.getValues().size());

        List<BatchUnitConvertRespVO.UnitConvertResultItem> results = new ArrayList<>();
        int successCount = 0;
        int failureCount = 0;

        // 1. 查询所有转换规则、关联关系和单位信息（只查询一次）
        List<UnitConversionDO> conversions = unitConversionMapper.selectList();
        List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
        List<UntInfoDO> units = untInfoMapper.selectList();

        for (BigDecimal value : reqVO.getValues()) {
            try {
                // 2. 使用工具类进行转换
                UnitConversionUtil.ConversionResult result = UnitConversionUtil.convertBySymbol(
                        value,
                        reqVO.getSrcUnitSymbol(),
                        reqVO.getTgtUnitSymbol(),
                        conversions,
                        relations,
                        units,
                        reqVO.getPrecision() != null ? reqVO.getPrecision() : 6
                );

                // 3. 构建成功结果
                results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
                        .success(true)
                        .data(UnitConvertRespVO.builder()
                                .srcUntSmb(reqVO.getSrcUnitSymbol())
                                .tgtUntSmb(reqVO.getTgtUnitSymbol())
                                .originalValue(value)
                                .convertedValue(result.getValue())
                                .factor(result.getFactor())
                                .strategy(result.getStrategy().name())
                                .build())
                        .build());
                successCount++;
            } catch (Exception e) {
                log.warn("按符号转换失败: 源单位符号={}, 目标单位符号={}, 值={}, 错误={}",
                        reqVO.getSrcUnitSymbol(), reqVO.getTgtUnitSymbol(), value, e.getMessage());

                // 4. 构建失败结果
                results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
                        .success(false)
                        .errorMessage(e.getMessage())
                        .build());
                failureCount++;

                // 5. 如果不忽略错误，直接抛出异常
                if (!Boolean.TRUE.equals(reqVO.getIgnoreErrors())) {
                    throw e;
                }
            }
        }

        return BatchUnitConvertRespVO.builder()
                .results(results)
                .successCount(successCount)
                .failureCount(failureCount)
                .totalCount(reqVO.getValues().size())
                .build();
    }

    @Override
    public BatchUnitConvertRespVO batchConvertByName(BatchUnitConvertByNameReqVO reqVO) {
        log.info("开始批量按名称转换: 源单位名称={}, 目标单位名称={}, 值数量={}",
                reqVO.getSrcUnitName(), reqVO.getTgtUnitName(), reqVO.getValues().size());

        List<BatchUnitConvertRespVO.UnitConvertResultItem> results = new ArrayList<>();
        int successCount = 0;
        int failureCount = 0;

        // 1. 查询所有转换规则、关联关系和单位信息（只查询一次）
        List<UnitConversionDO> conversions = unitConversionMapper.selectList();
        List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList();
        List<UntInfoDO> units = untInfoMapper.selectList();

        for (BigDecimal value : reqVO.getValues()) {
            try {
                // 2. 使用工具类进行转换
                UnitConversionUtil.ConversionResult result = UnitConversionUtil.convertByName(
                        value,
                        reqVO.getSrcUnitName(),
                        reqVO.getTgtUnitName(),
                        conversions,
                        relations,
                        units,
                        reqVO.getPrecision() != null ? reqVO.getPrecision() : 6
                );

                // 3. 构建成功结果
                results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
                        .success(true)
                        .data(UnitConvertRespVO.builder()
                                .srcUntName(reqVO.getSrcUnitName())
                                .tgtUntName(reqVO.getTgtUnitName())
                                .originalValue(value)
                                .convertedValue(result.getValue())
                                .factor(result.getFactor())
                                .strategy(result.getStrategy().name())
                                .build())
                        .build());
                successCount++;
            } catch (Exception e) {
                log.warn("按名称转换失败: 源单位名称={}, 目标单位名称={}, 值={}, 错误={}",
                        reqVO.getSrcUnitName(), reqVO.getTgtUnitName(), value, e.getMessage());

                // 4. 构建失败结果
                results.add(BatchUnitConvertRespVO.UnitConvertResultItem.builder()
                        .success(false)
                        .errorMessage(e.getMessage())
                        .build());
                failureCount++;

                // 5. 如果不忽略错误，直接抛出异常
                if (!Boolean.TRUE.equals(reqVO.getIgnoreErrors())) {
                    throw e;
                }
            }
        }

        return BatchUnitConvertRespVO.builder()
                .results(results)
                .successCount(successCount)
                .failureCount(failureCount)
                .totalCount(reqVO.getValues().size())
                .build();
    }

    @Override
    public UnitConversionValidationRespVO validateConversionPaths(Long quantityId) {
        log.info("开始校验量纲 {} 的转换路径", quantityId);

        // 1. 查询量纲信息
        UnitQuantityDO quantity = unitQuantityService.getUnitQuantity(quantityId);
        if (quantity == null) {
            throw exception(UNIT_QUANTITY_NOT_EXISTS);
        }

        // 2. 查询该量纲下的所有单位
        List<QuantityUnitRelationDO> relations = quantityUnitRelationMapper.selectList(
                new LambdaQueryWrapperX<QuantityUnitRelationDO>()
                        .eq(QuantityUnitRelationDO::getUntQtyId, quantityId)
        );

        if (CollUtil.isEmpty(relations)) {
            return buildEmptyValidationResult(quantityId, quantity);
        }

        // 3. 获取单位详细信息
        List<Long> unitIds = relations.stream()
                .map(QuantityUnitRelationDO::getUntId)
                .collect(Collectors.toList());
        List<UntInfoDO> units = untInfoMapper.selectByIds(unitIds);
        Map<Long, UntInfoDO> unitMap = units.stream()
                .collect(Collectors.toMap(UntInfoDO::getId, u -> u));

        // 4. 找到基准单位
        QuantityUnitRelationDO baseRelation = relations.stream()
                .filter(r -> r.getIsBse() == 1)
                .findFirst()
                .orElse(null);

        UnitConversionValidationRespVO.BaseUnitInfo baseUnitInfo = null;
        Long baseUnitId = null;
        if (baseRelation != null) {
            UntInfoDO baseUnit = unitMap.get(baseRelation.getUntId());
            baseUnitId = baseRelation.getUntId();
            if (baseUnit != null) {
                baseUnitInfo = UnitConversionValidationRespVO.BaseUnitInfo.builder()
                        .unitId(baseUnit.getId())
                        .unitName(baseUnit.getName())
                        .unitSymbol(baseUnit.getSmb())
                        .build();
            }
        }

        // 5. 查询该量纲下的所有转换规则
        List<UnitConversionDO> conversions = unitConversionMapper.selectList(
                new LambdaQueryWrapperX<UnitConversionDO>()
                        .eq(UnitConversionDO::getUntQtyId, quantityId)
        );

        // 6. 检查所有单位对之间的转换路径（两两互相转换）
        List<UnitConversionValidationRespVO.UnconvertibleUnitInfo> unconvertibleUnits = new ArrayList<>();
        List<UnitConversionValidationRespVO.ConversionPathInfo> conversionPaths = new ArrayList<>();

        // 统计：能够互相转换的单位数量
        Set<Long> fullyConvertibleUnits = new HashSet<>();

        // 遍历所有单位对
        for (int i = 0; i < units.size(); i++) {
            UntInfoDO srcUnit = units.get(i);
            boolean canConvertToAll = true;

            for (int j = 0; j < units.size(); j++) {
                if (i == j) continue; // 跳过自己

                UntInfoDO tgtUnit = units.get(j);

                // 尝试转换（使用工具类）
                boolean canConvert = canConvert(srcUnit.getId(), tgtUnit.getId(), conversions, relations, baseUnitId);

                if (!canConvert) {
                    canConvertToAll = false;
                    // 只记录第一个方向的失败（避免重复：A→B 和 B→A）
                    if (i < j) {
                        unconvertibleUnits.add(UnitConversionValidationRespVO.UnconvertibleUnitInfo.builder()
                                .unitId(srcUnit.getId())
                                .unitName(srcUnit.getName())
                                .unitSymbol(srcUnit.getSmb())
                                .reason(String.format("无法转换到 %s", tgtUnit.getName()))
                                .build());
                    }
                } else {
                    // 记录转换路径（只记录到基准单位的路径，避免太多）
                    if (baseUnitId != null && tgtUnit.getId().equals(baseUnitId)) {
                        String strategy = getConversionStrategy(srcUnit.getId(), tgtUnit.getId(), conversions, baseUnitId);
                        conversionPaths.add(UnitConversionValidationRespVO.ConversionPathInfo.builder()
                                .srcUnitId(srcUnit.getId())
                                .srcUnitName(srcUnit.getName())
                                .tgtUnitId(tgtUnit.getId())
                                .tgtUnitName(tgtUnit.getName())
                                .hasDirect(strategy.equals("DIRECT"))
                                .hasViaBase(strategy.equals("VIA_BASE_UNIT"))
                                .pathDescription(srcUnit.getName() + " → " + tgtUnit.getName() +
                                        (strategy.equals("DIRECT") ? " (直接转换)" : " (通过基准单位)"))
                                .build());
                    }
                }
            }

            if (canConvertToAll) {
                fullyConvertibleUnits.add(srcUnit.getId());
            }
        }

        // 7. 构建响应
        return UnitConversionValidationRespVO.builder()
                .quantityId(quantityId)
                .quantityName(quantity.getName())
                .quantitySymbol(quantity.getSymbol())
                .totalUnits(units.size())
                .convertibleUnits(fullyConvertibleUnits.size())
                .unconvertibleUnits(units.size() - fullyConvertibleUnits.size())
                .allConvertible(fullyConvertibleUnits.size() == units.size())
                .baseUnit(baseUnitInfo)
                .unconvertibleUnitList(unconvertibleUnits)
                .conversionPaths(conversionPaths)
                .build();
    }

    /**
     * 检查两个单位是否能够转换（考虑反向推导）
     */
    private boolean canConvert(Long srcUnitId, Long tgtUnitId,
                               List<UnitConversionDO> conversions,
                               List<QuantityUnitRelationDO> relations,
                               Long baseUnitId) {
        // 1. 检查直接转换（正向）
        boolean hasDirectForward = conversions.stream()
                .anyMatch(c -> c.getSrcUntId().equals(srcUnitId) && c.getTgtUntId().equals(tgtUnitId));
        if (hasDirectForward) {
            return true;
        }

        // 2. 检查直接转换（反向，可以推导）
        boolean hasDirectReverse = conversions.stream()
                .anyMatch(c -> c.getSrcUntId().equals(tgtUnitId) && c.getTgtUntId().equals(srcUnitId));
        if (hasDirectReverse) {
            return true;
        }

        // 3. 检查通过基准单位的间接转换
        if (baseUnitId == null) {
            return false;
        }

        // 如果源单位是基准单位
        if (srcUnitId.equals(baseUnitId)) {
            // 检查是否有 基准 → 目标 的转换规则（正向或反向）
            boolean hasBaseToTgt = conversions.stream()
                    .anyMatch(c -> c.getSrcUntId().equals(baseUnitId) && c.getTgtUntId().equals(tgtUnitId));
            boolean hasTgtToBase = conversions.stream()
                    .anyMatch(c -> c.getSrcUntId().equals(tgtUnitId) && c.getTgtUntId().equals(baseUnitId));
            return hasBaseToTgt || hasTgtToBase;
        }

        // 如果目标单位是基准单位
        if (tgtUnitId.equals(baseUnitId)) {
            // 检查是否有 源 → 基准 的转换规则（正向或反向）
            boolean hasSrcToBase = conversions.stream()
                    .anyMatch(c -> c.getSrcUntId().equals(srcUnitId) && c.getTgtUntId().equals(baseUnitId));
            boolean hasBaseToSrc = conversions.stream()
                    .anyMatch(c -> c.getSrcUntId().equals(baseUnitId) && c.getTgtUntId().equals(srcUnitId));
            return hasSrcToBase || hasBaseToSrc;
        }

        // 两者都不是基准单位，需要两步转换：源 → 基准 → 目标
        // 检查 源 → 基准（正向或反向）
        boolean srcToBase = conversions.stream()
                .anyMatch(c -> c.getSrcUntId().equals(srcUnitId) && c.getTgtUntId().equals(baseUnitId));
        boolean baseToSrc = conversions.stream()
                .anyMatch(c -> c.getSrcUntId().equals(baseUnitId) && c.getTgtUntId().equals(srcUnitId));

        // 检查 基准 → 目标（正向或反向）
        boolean baseToTgt = conversions.stream()
                .anyMatch(c -> c.getSrcUntId().equals(baseUnitId) && c.getTgtUntId().equals(tgtUnitId));
        boolean tgtToBase = conversions.stream()
                .anyMatch(c -> c.getSrcUntId().equals(tgtUnitId) && c.getTgtUntId().equals(baseUnitId));

        return (srcToBase || baseToSrc) && (baseToTgt || tgtToBase);
    }

    /**
     * 获取转换策略
     */
    private String getConversionStrategy(Long srcUnitId, Long tgtUnitId,
                                         List<UnitConversionDO> conversions,
                                         Long baseUnitId) {
        // 检查直接转换
        boolean hasDirect = conversions.stream()
                .anyMatch(c -> c.getSrcUntId().equals(srcUnitId) && c.getTgtUntId().equals(tgtUnitId));
        if (hasDirect) {
            return "DIRECT";
        }
        return "VIA_BASE_UNIT";
    }

    private UnitConversionValidationRespVO buildEmptyValidationResult(Long quantityId, UnitQuantityDO quantity) {
        return UnitConversionValidationRespVO.builder()
                .quantityId(quantityId)
                .quantityName(quantity.getName())
                .quantitySymbol(quantity.getSymbol())
                .totalUnits(0)
                .convertibleUnits(0)
                .unconvertibleUnits(0)
                .allConvertible(true)
                .baseUnit(null)
                .unconvertibleUnitList(new ArrayList<>())
                .conversionPaths(new ArrayList<>())
                .build();
    }

}