package com.usky.vpp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.usky.vpp.constant.VppDrEventStatus;
import com.usky.vpp.domain.VppCustomerContact;
import com.usky.vpp.domain.VppDrEvent;
import com.usky.vpp.domain.VppDrInvitation;
import com.usky.vpp.domain.VppSite;
import com.usky.vpp.mapper.VppCustomerContactMapper;
import com.usky.vpp.mapper.VppDrInvitationMapper;
import com.usky.vpp.mapper.VppSiteMapper;
import com.usky.vpp.service.VppDrUnInvitationIngestService;
import com.usky.vpp.util.VppAuditHelper;
import com.usky.vpp.util.VppDrParticipationHelper;
import com.usky.vpp.util.VppUnEventParser;
import com.usky.vpp.util.VppUnPayloadHelper;
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.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

@Service
public class VppDrUnInvitationIngestServiceImpl implements VppDrUnInvitationIngestService {

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

    private static final int REPLY_PENDING = 0;
    private static final int RESPONSE_PENDING = VppDrEventStatus.PENDING;
    private static final int SMS_NOT_SENT = 0;

    @Autowired
    private VppDrInvitationMapper invitationMapper;
    @Autowired
    private VppSiteMapper siteMapper;
    @Autowired
    private VppCustomerContactMapper contactMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncInvitationsFromUnEvent(VppDrEvent event, Map<String, Object> eventMap) {
        if (event == null || event.getId() == null || eventMap == null) {
            return;
        }
        List<String> unResourceIds = VppUnEventParser.getTargetResourceIds(eventMap);
        if (unResourceIds.isEmpty()) {
            return;
        }

        Map<String, Object> descriptor = VppUnEventParser.getDescriptor(eventMap);
        LocalDateTime[] period = VppUnEventParser.resolveActivePeriod(eventMap);
        LocalDate executeStart = resolveExecuteDate(period[0], event.getStartTime());
        LocalDate executeEnd = resolveExecuteDate(period[1], event.getEndTime());
        if (executeStart == null) {
            log.warn("UN 邀约缺少执行开始时间 eventId={}", event.getEventId());
            return;
        }
        if (executeEnd == null) {
            executeEnd = executeStart;
        }
        LocalDateTime replyDeadline = VppUnPayloadHelper.getDateTime(descriptor, "deadline");
        if (replyDeadline == null && event.getStartTime() != null) {
            replyDeadline = event.getStartTime();
        }
        if (replyDeadline == null) {
            log.warn("UN 邀约缺少回复截止时间 eventId={}", event.getEventId());
            return;
        }

        BigDecimal demandCapacityKw = resolveUnDemandCapacityKw(event, eventMap);
        for (String unResourceId : unResourceIds) {
            syncSingleUnInvitation(event, unResourceId, executeStart, executeEnd, replyDeadline, demandCapacityKw);
        }
    }

    private void syncSingleUnInvitation(VppDrEvent event,
                                        String resourceId,
                                        LocalDate executeStart,
                                        LocalDate executeEnd,
                                        LocalDateTime replyDeadline,
                                        BigDecimal demandCapacityKw) {
        VppSite site = siteMapper.selectOne(new LambdaQueryWrapper<VppSite>()
                .eq(VppSite::getAccountNo, resourceId.trim())
                .eq(VppSite::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .last("LIMIT 1"));
        if (site == null) {
            log.warn("UN resourceID 未匹配站点 unResourceId={} eventId={}", resourceId, event.getEventId());
            return;
        }
        if (site.getCustomerId() == null) {
            log.warn("站点缺少 customerId siteId={} unResourceId={}", site.getId(), resourceId);
            return;
        }
        if (findExistingInvitation(event.getId(), site.getId(), site.getCustomerId()) != null) {
            log.debug("邀约已存在，跳过 eventPk={} siteId={}", event.getId(), site.getId());
            return;
        }

        VppDrInvitation invitation = new VppDrInvitation();
        invitation.setInvitationNo(VppAuditHelper.nextInvitationNo());
        invitation.setDrEventId(event.getId());
        invitation.setCustomerId(site.getCustomerId());
        invitation.setSiteId(site.getId());
        invitation.setExecuteStartDate(executeStart);
        invitation.setExecuteEndDate(executeEnd);
        invitation.setReplyDeadline(shiftOneHourEarlier(replyDeadline));
        invitation.setIssueTime(shiftOneHourEarlier(LocalDateTime.now()));
        invitation.setTransactionType(event.getEventType());
        invitation.setResponseType(event.getResponseType());
        invitation.setDemandCapacityKw(demandCapacityKw);
        invitation.setDeclaredCapacityKw(BigDecimal.ZERO);
        invitation.setReplyStatus(REPLY_PENDING);
        invitation.setResponseStatus(RESPONSE_PENDING);
        invitation.setSmsNotifyStatus(SMS_NOT_SENT);
        invitation.setSmsContactId(resolveSmsContactId(site.getCustomerId()));
        invitation.setEstimatedCompletionRate(VppDrParticipationHelper.calcEstimatedCompletionRate(null, null));
        invitation.setResponseCompletionRate(VppDrParticipationHelper.calcResponseCompletionRate(null, null));
        invitation.setRemark("UN邀约 resourceID=" + resourceId);
        VppAuditHelper.fillCreate(invitation);
        if (event.getTenantId() != null) {
            invitation.setTenantId(event.getTenantId());
        }
        invitationMapper.insert(invitation);
        log.info("UN 邀约已入库 eventId={} siteId={} unResourceId={}", event.getEventId(), site.getId(), resourceId);
    }

    private Long resolveSmsContactId(Long customerId) {
        if (customerId == null) {
            return null;
        }
        VppCustomerContact primary = contactMapper.selectOne(new LambdaQueryWrapper<VppCustomerContact>()
                .eq(VppCustomerContact::getCustomerId, customerId)
                .eq(VppCustomerContact::getIsPrimary, 1)
                .eq(VppCustomerContact::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .last("LIMIT 1"));
        if (primary != null) {
            return primary.getId();
        }
        VppCustomerContact any = contactMapper.selectOne(new LambdaQueryWrapper<VppCustomerContact>()
                .eq(VppCustomerContact::getCustomerId, customerId)
                .eq(VppCustomerContact::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .last("LIMIT 1"));
        return any != null ? any.getId() : null;
    }

    private LocalDate resolveExecuteDate(LocalDateTime fromPeriod, LocalDateTime fromEvent) {
        if (fromPeriod != null) {
            return fromPeriod.toLocalDate();
        }
        return fromEvent != null ? fromEvent.toLocalDate() : null;
    }

    /** UN 报文时间与平台展示/业务规则校正：向前（提前）1 小时。 */
    private static LocalDateTime shiftOneHourEarlier(LocalDateTime time) {
        return time != null ? time.minusHours(1) : null;
    }

    private BigDecimal resolveUnDemandCapacityKw(VppDrEvent event, Map<String, Object> eventMap) {
        BigDecimal demand = VppUnEventParser.extractDemandChargeKw(eventMap);
        if (demand == null || demand.compareTo(BigDecimal.ZERO) <= 0) {
            demand = event.getTargetCapacityKw();
        }
        if (demand == null || demand.compareTo(BigDecimal.ZERO) <= 0) {
            demand = BigDecimal.ONE;
        }
        return demand;
    }

    private VppDrInvitation findExistingInvitation(Long drEventId, Long siteId, Long customerId) {
        LambdaQueryWrapper<VppDrInvitation> wrapper = new LambdaQueryWrapper<VppDrInvitation>()
                .eq(VppDrInvitation::getDrEventId, drEventId)
                .eq(VppDrInvitation::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .last("LIMIT 1");
        if (siteId != null) {
            wrapper.eq(VppDrInvitation::getSiteId, siteId);
        } else {
            wrapper.eq(VppDrInvitation::getCustomerId, customerId);
        }
        return invitationMapper.selectOne(wrapper);
    }
}
