package cn.iocoder.foodnexus.module.order.service.orderScore;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.foodnexus.framework.common.enums.CommonStatusEnum;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.pojo.CommonResult;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpAuditStatus;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierSimpleRespVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpSupplierDO;
import cn.iocoder.foodnexus.module.erp.service.purchase.ErpSupplierService;
import cn.iocoder.foodnexus.module.operations.dal.dataobject.scoringweight.ScoringWeightDO;
import cn.iocoder.foodnexus.module.operations.service.scoringweight.ScoringWeightService;
import cn.iocoder.foodnexus.module.order.api.OrderScoreApi;
import cn.iocoder.foodnexus.module.order.dal.dataobject.customerorder.CustomerOrderDO;
import cn.iocoder.foodnexus.module.order.dal.mysql.customerorder.CustomerOrderMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.foodnexus.module.order.controller.admin.orderScore.vo.*;
import cn.iocoder.foodnexus.module.order.dal.dataobject.orderScore.OrderScoreDO;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;

import cn.iocoder.foodnexus.module.order.dal.mysql.orderScore.OrderScoreMapper;

import static cn.iocoder.foodnexus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.foodnexus.framework.common.pojo.PageParam.PAGE_SIZE_NONE;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.diffList;
import static cn.iocoder.foodnexus.module.order.enums.ErrorCodeConstants.*;

/**
 * 订单评价 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
public class OrderScoreServiceImpl implements OrderScoreService, OrderScoreApi {

    @Resource
    private OrderScoreMapper scoreMapper;

    @Autowired
    private ErpSupplierService supplierService;

    @Autowired
    private ScoringWeightService scoringWeightService;

    @Autowired
    private CustomerOrderMapper customerOrderMapper;

    @Override
    public Long createScore(OrderScoreSaveReqVO createReqVO) {
        // 插入
        OrderScoreDO score = BeanUtils.toBean(createReqVO, OrderScoreDO.class);
        scoreMapper.insert(score);

        // 返回
        return score.getId();
    }

    @Override
    public void updateScore(OrderScoreSaveReqVO updateReqVO) {
        // 校验存在
        validateScoreExists(updateReqVO.getId());
        // 更新
        OrderScoreDO updateObj = BeanUtils.toBean(updateReqVO, OrderScoreDO.class);
        scoreMapper.updateById(updateObj);
    }

    @Override
    public void deleteScore(Long id) {
        // 校验存在
        validateScoreExists(id);
        // 删除
        scoreMapper.deleteById(id);
    }

    @Override
        public void deleteScoreListByIds(List<Long> ids) {
        // 删除
        scoreMapper.deleteByIds(ids);
        }


    private void validateScoreExists(Long id) {
        if (scoreMapper.selectById(id) == null) {
            throw exception(SCORE_NOT_EXISTS);
        }
    }

    @Override
    public OrderScoreDO getScore(Long id) {
        return scoreMapper.selectById(id);
    }

    @Override
    public PageResult<OrderScoreDO> getScorePage(OrderScorePageReqVO pageReqVO) {
        return scoreMapper.selectPage(pageReqVO);
    }

    @Override
    public Integer queryScore(Long customerOrderId, Long scoreId) {
        OrderScoreDO orderScoreDO = scoreMapper.selectOne(Wrappers.<OrderScoreDO>lambdaQuery()
                .eq(OrderScoreDO::getOrderId, customerOrderId)
                .eq(OrderScoreDO::getScoreId, scoreId));
        return Optional.ofNullable(orderScoreDO).map(OrderScoreDO::getScore).orElse(null);
    }

    @Override
    public boolean exists(Long customerOrderId, Long scoreId) {
        return scoreMapper.exists(Wrappers.<OrderScoreDO>lambdaQuery()
                .eq(OrderScoreDO::getOrderId, customerOrderId)
                .eq(OrderScoreDO::getScoreId, scoreId));
    }

    @Override
    public PageResult<OrderScoreSupplierRespVO> supplierPage(OrderScoreSupplierPageReqVO pageReqVO) {
        ErpSupplierPageReqVO supplierPageReqVO = BeanUtils.toBean(pageReqVO, ErpSupplierPageReqVO.class);
        supplierPageReqVO.setAuditStatus(ErpAuditStatus.APPROVE.getStatus().toString());
        // supplierPageReqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
        PageResult<ErpSupplierDO> supplierPage = supplierService.getSupplierPage(supplierPageReqVO);
        if (CommonUtil.isNotEmpty(supplierPage.getList())) {
            Map<Long, ErpSupplierDO> supplierMap = CommonUtil.listConvertMap(supplierPage.getList(), ErpSupplierDO::getId);
            List<ScoringWeightDO> scoringWeightDOS = scoringWeightService.listAll();
            Map<Long, ScoringWeightDO> scoringWeightMap = CommonUtil.listConvertMap(scoringWeightDOS, ScoringWeightDO::getId);

            List<OrderScoreSupplierRespVO> resultList = new ArrayList<>();

            // 解析年份
            int year = Integer.parseInt(pageReqVO.getYear());

            // 当年的第一天 00:00:00
            LocalDateTime startOfYear = LocalDateTime.of(year, 1, 1, 0, 0, 0);

            // 当年的最后一天 23:59:59.999999999
            LocalDateTime endOfYear = LocalDateTime.of(year, 12, 1, 23, 59, 59)
                    .with(TemporalAdjusters.lastDayOfMonth())
                    .withNano(999_999_999);

            for (Map.Entry<Long, ErpSupplierDO> e : supplierMap.entrySet()) {
                BigDecimal finalScore = BigDecimal.ZERO;
                Long supplierId = e.getKey();
                ErpSupplierDO supplierInfo = e.getValue();
                List<OrderScoreSupplierRespVO.ScoreItems> items = new ArrayList<>();
                OrderScoreSupplierRespVO orderScoreSupplier = new OrderScoreSupplierRespVO();
                orderScoreSupplier.setYear(pageReqVO.getYear());
                orderScoreSupplier.setSupplierId(supplierId);
                orderScoreSupplier.setSupplierInfo(BeanUtil.toBean(supplierInfo, ErpSupplierSimpleRespVO.class));
                List<OrderScoreDO> orderScores = scoreMapper.selectList(Wrappers.<OrderScoreDO>lambdaQuery()
                        .eq(OrderScoreDO::getSupplierId, supplierId)
                        .between(OrderScoreDO::getCreateTime, startOfYear, endOfYear));
                Map<Long, List<OrderScoreDO>> scoreSupplierMap = CommonUtil.listConvertListMap(orderScores, OrderScoreDO::getScoreId);
                for (Map.Entry<Long, ScoringWeightDO> entry : scoringWeightMap.entrySet()) {
                    Long scoreId = entry.getKey();
                    ScoringWeightDO scoreInfo = entry.getValue();
                    if (scoreId == 100L) {
                        finalScore = finalScore.add(this.calculate(BigDecimal.valueOf(Optional.ofNullable(supplierInfo.getAuditScore()).orElse(0)), scoreInfo.getWeightRatio()));
                    } else {
                        OrderScoreSupplierRespVO.ScoreItems scoreItem = new OrderScoreSupplierRespVO.ScoreItems();
                        List<OrderScoreDO> supplierScores = scoreSupplierMap.get(scoreId);
                        if (CommonUtil.isNotEmpty(supplierScores)) {
                            scoreItem.setAllScore(supplierScores.stream().mapToInt(OrderScoreDO::getScore).sum());
                            scoreItem.setScoreCount(supplierScores.size());
                            scoreItem.setScore(this.divideInts(scoreItem.getAllScore(), scoreItem.getScoreCount()));
                        }
                        scoreItem.setScoreId(scoreId);
                        scoreItem.setScoreName(scoreInfo.getScoreName() + "(" + UserSystemEnum.getByKey(scoreInfo.getUserSystem()).getLabel() + ")");
                        items.add(scoreItem);
                        if (CommonUtil.isNotEmpty(scoreItem.getScore()) && scoreInfo.getWeightRatio().compareTo(BigDecimal.ZERO) > 0) {
                            finalScore = finalScore.add(this.calculate(scoreItem.getScore(), scoreInfo.getWeightRatio()));
                        }
                    }
                }
                orderScoreSupplier.setScoreItems(items);
                orderScoreSupplier.setFinalScore(finalScore);
                resultList.add(orderScoreSupplier);
            }
            return new PageResult<>(resultList, supplierPage.getTotal());
        }
        return null;
    }


    @Override
    public Long queryTopSupplierRank(List<Long> ids) {
        OrderScoreSupplierPageReqVO reqVO = new OrderScoreSupplierPageReqVO();
        reqVO.setIdList(ids);
        LocalDate today = LocalDate.now();
        int year = today.getYear();
        reqVO.setYear(String.valueOf(year));
        reqVO.setPageNo(1);
        reqVO.setPageSize(PAGE_SIZE_NONE);
        PageResult<OrderScoreSupplierRespVO> result = this.supplierPage(reqVO);
        if (CommonUtil.isEmpty(result) || CommonUtil.isEmpty(result.getList())) {
            return ids.get(0);
        } else {
            List<OrderScoreSupplierRespVO> list = result.getList();
            // 按 finalScore 降序排序
            list.sort((s1, s2) ->
                    s2.getFinalScore().compareTo(s1.getFinalScore()));
            return list.get(0).getSupplierId();
        }
    }

    @Override
    public List<OrderScoreDO> listByOrderId(Long id) {
        return scoreMapper.selectList(OrderScoreDO::getOrderId, id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteByOrderId(Long orderId) {
        if (!scoreMapper.exists(Wrappers.<OrderScoreDO>lambdaQuery()
                .eq(OrderScoreDO::getOrderId, orderId))) {
            return Boolean.FALSE;
        }
        customerOrderMapper.update(Wrappers.<CustomerOrderDO>lambdaUpdate()
                .set(CustomerOrderDO::getHasScore, Boolean.FALSE)
                .eq(CustomerOrderDO::getId, orderId));
        return scoreMapper.delete(Wrappers.<OrderScoreDO>lambdaQuery()
                .eq(OrderScoreDO::getOrderId, orderId)) > 0;
    }

    public BigDecimal divideInts(int num1, int num2) {
        // 处理除数为0的情况
        if (num2 == 0) {
            return BigDecimal.ZERO;
        }

        // 将int转换为BigDecimal
        BigDecimal dividend = BigDecimal.valueOf(num1);
        BigDecimal divisor = BigDecimal.valueOf(num2);

        // 相除并保留两位小数，使用四舍五入模式
        return dividend.divide(divisor, 2, RoundingMode.HALF_UP);
    }

    public BigDecimal calculate(BigDecimal num1, BigDecimal num2) {
        // 处理空值情况
        if (num1 == null || num2 == null) {
            return BigDecimal.ZERO;
        }

        // 1. 乘法运算
        BigDecimal product = num1.multiply(num2);

        // 2. 除以100，保留两位小数，使用四舍五入模式
        BigDecimal result = product.divide(
                new BigDecimal("100"),  // 除数100
                2,                      // 保留两位小数
                RoundingMode.HALF_UP    // 四舍五入模式
        );

        return result;
    }
}