package com.usky.vpp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.usky.common.core.bean.CommonPage;
import com.usky.common.core.exception.BusinessException;
import com.usky.vpp.domain.VppDrEvent;
import com.usky.vpp.domain.VppDrInvitation;
import com.usky.vpp.domain.VppDrSubsidyPrediction;
import com.usky.vpp.domain.VppSite;
import com.usky.vpp.mapper.VppDrEventMapper;
import com.usky.vpp.mapper.VppDrInvitationMapper;
import com.usky.vpp.mapper.VppDrSubsidyPredictionMapper;
import com.usky.vpp.mapper.VppSiteMapper;
import com.usky.vpp.service.VppDrSubsidyPredictionService;
import com.usky.vpp.service.vo.DrSubsidyPredictionVO;
import com.usky.vpp.util.VppAuditHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 补贴金额预测 业务实现
 */
@Service
public class VppDrSubsidyPredictionServiceImpl implements VppDrSubsidyPredictionService {

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

    @Autowired
    private VppDrSubsidyPredictionMapper subsidyPredictionMapper;
    @Autowired
    private VppDrInvitationMapper invitationMapper;
    @Autowired
    private VppDrEventMapper eventMapper;
    @Autowired
    private VppSiteMapper siteMapper;

    @Override
    public CommonPage<DrSubsidyPredictionVO> page(String siteName, String startTime, String endTime,
                                                   Integer current, Integer size) {
        Page<VppDrSubsidyPrediction> page = new Page<>(
                current != null ? current : 1,
                size != null && size <= 100 ? size : 20);

        LambdaQueryWrapper<VppDrSubsidyPrediction> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.hasText(siteName)) {
            wrapper.like(VppDrSubsidyPrediction::getSiteName, siteName);
        }
        if (StringUtils.hasText(startTime)) {
            wrapper.ge(VppDrSubsidyPrediction::getEventStartTime, startTime);
        }
        if (StringUtils.hasText(endTime)) {
            wrapper.le(VppDrSubsidyPrediction::getEventStartTime, endTime);
        }
        wrapper.orderByDesc(VppDrSubsidyPrediction::getCreateTime);

        Page<VppDrSubsidyPrediction> result = subsidyPredictionMapper.selectPage(page, wrapper);

        List<DrSubsidyPredictionVO> list = result.getRecords().stream()
                .map(this::toVo)
                .collect(Collectors.toList());

        return new CommonPage<>(list, result.getTotal(), size != null ? size : 20, current != null ? current : 1);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
    public void generateByEventId(Long drEventId) {
        if (drEventId == null) {
            throw new BusinessException("事件ID不能为空");
        }

        // 查询事件
        VppDrEvent event = eventMapper.selectById(drEventId);
        if (event == null) {
            log.warn("补贴预测生成跳过：事件不存在 drEventId={}", drEventId);
            return;
        }

        // 查询事件下所有邀约
        List<VppDrInvitation> invitations = invitationMapper.selectList(
                new LambdaQueryWrapper<VppDrInvitation>()
                        .eq(VppDrInvitation::getDrEventId, drEventId)
                        .eq(VppDrInvitation::getDeleteFlag, VppAuditHelper.NOT_DELETED)
        );

        if (invitations.isEmpty()) {
            log.info("补贴预测生成跳过：事件下无邀约 drEventId={}", drEventId);
            return;
        }

        // 批量查询站点名称
        Set<Long> siteIds = invitations.stream()
                .map(VppDrInvitation::getSiteId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Map<Long, String> siteNameMap = siteIds.isEmpty() ? Collections.emptyMap()
                : siteMapper.selectBatchIds(siteIds).stream()
                        .collect(Collectors.toMap(VppSite::getId, VppSite::getSiteName, (a, b) -> a));

        // 逐条计算并 upsert
        for (VppDrInvitation invitation : invitations) {
            VppDrSubsidyPrediction prediction = buildPrediction(event, invitation, siteNameMap);

            // 按 invitation_id 唯一键，存在则更新，不存在则新增
            VppDrSubsidyPrediction existing = subsidyPredictionMapper.selectOne(
                    new LambdaQueryWrapper<VppDrSubsidyPrediction>()
                            .eq(VppDrSubsidyPrediction::getInvitationId, invitation.getId())
            );

            if (existing != null) {
                prediction.setId(existing.getId());
                prediction.setUpdateTime(LocalDateTime.now());
                subsidyPredictionMapper.updateById(prediction);
            } else {
                prediction.setCreateTime(LocalDateTime.now());
                prediction.setUpdateTime(LocalDateTime.now());
                subsidyPredictionMapper.insert(prediction);
            }
        }

        log.info("补贴预测生成完成 drEventId={}, invitationCount={}", drEventId, invitations.size());
    }

    /**
     * 构建单条补贴预测记录
     */
    private VppDrSubsidyPrediction buildPrediction(VppDrEvent event, VppDrInvitation invitation,
                                                    Map<Long, String> siteNameMap) {
        VppDrSubsidyPrediction p = new VppDrSubsidyPrediction();
        p.setInvitationId(invitation.getId());
        p.setDrEventId(event.getId());
        p.setSiteId(invitation.getSiteId());
        p.setSiteName(invitation.getSiteId() == null
                ? null
                : siteNameMap.getOrDefault(invitation.getSiteId(), null));
        p.setEventStartTime(event.getStartTime());
        p.setEventEndTime(event.getEndTime());

        // 响应时长（分钟）
        int durationMin = 0;
        if (event.getStartTime() != null && event.getEndTime() != null
                && event.getEndTime().isAfter(event.getStartTime())) {
            durationMin = (int) Duration.between(event.getStartTime(), event.getEndTime()).toMinutes();
        }
        p.setResponseDurationMin(durationMin);

        // 补贴标准
        p.setSubsidyPrice(event.getSubsidyPrice());

        // 预估响应容量
        p.setEstimatedCapacityKw(invitation.getEstimatedResponseCapacityKw());

        // 实际出清
        p.setClearedCapacityKw(invitation.getActualClearedCapacityKw());

        // 预估完成率 = 预估容量 / 实际出清；实际出清为NULL或0时记为0
        BigDecimal completionRate = BigDecimal.ZERO;
        BigDecimal estimatedKw = invitation.getEstimatedResponseCapacityKw();
        BigDecimal actualKw = invitation.getActualClearedCapacityKw();
        if (estimatedKw != null && actualKw != null && actualKw.compareTo(BigDecimal.ZERO) > 0) {
            completionRate = estimatedKw.divide(actualKw, 4, RoundingMode.HALF_UP);
        }
        p.setCompletionRate(completionRate);

        // 预估偏差率 = 1 - 预估完成率
        BigDecimal deviationRate = BigDecimal.ONE.subtract(completionRate);
        p.setDeviationRate(deviationRate);

        // 预估补贴金额 = 补贴标准（为NULL时记为NULL）
        p.setEstimatedSubsidyAmount(event.getSubsidyPrice());

        p.setTenantId(event.getTenantId());
        return p;
    }

    private DrSubsidyPredictionVO toVo(VppDrSubsidyPrediction entity) {
        DrSubsidyPredictionVO vo = new DrSubsidyPredictionVO();
        vo.setId(entity.getId());
        vo.setInvitationId(entity.getInvitationId());
        vo.setDrEventId(entity.getDrEventId());
        vo.setSiteId(entity.getSiteId());
        vo.setSiteName(entity.getSiteName());
        vo.setEventStartTime(entity.getEventStartTime());
        vo.setEventEndTime(entity.getEventEndTime());
        vo.setResponseDurationMin(entity.getResponseDurationMin());
        vo.setSubsidyPrice(entity.getSubsidyPrice());
        vo.setEstimatedCapacityKw(entity.getEstimatedCapacityKw());
        vo.setClearedCapacityKw(entity.getClearedCapacityKw());
        vo.setCompletionRate(entity.getCompletionRate());
        vo.setDeviationRate(entity.getDeviationRate());
        vo.setEstimatedSubsidyAmount(entity.getEstimatedSubsidyAmount());
        vo.setCreateTime(entity.getCreateTime());
        vo.setUpdateTime(entity.getUpdateTime());
        return vo;
    }
}
