package com.usky.vpp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.usky.common.core.exception.BusinessException;
import com.usky.vpp.client.VppUnClient;
import com.usky.vpp.client.VppUnTokenHolder;
import com.usky.vpp.config.VppUnProperties;
import com.usky.vpp.config.VppUnPropertiesRegistry;
import com.usky.vpp.domain.VppDrEvent;
import com.usky.vpp.domain.VppDrParticipation;
import com.usky.vpp.domain.VppRegistration;
import com.usky.vpp.domain.VppResourcePoint;
import com.usky.vpp.domain.VppSite;
import com.usky.vpp.mapper.VppDrEventMapper;
import com.usky.vpp.mapper.VppDrParticipationMapper;
import com.usky.vpp.mapper.VppRegistrationMapper;
import com.usky.vpp.mapper.VppResourcePointMapper;
import com.usky.vpp.mapper.VppSiteMapper;
import com.usky.vpp.service.VppDrEventIngestService;
import com.usky.vpp.service.VppUnIntegrationService;
import com.usky.vpp.service.VppUnReportService;
import com.usky.vpp.util.VppAuditHelper;
import com.usky.vpp.util.VppUnMessageBuilder;
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 org.springframework.util.StringUtils;

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

@Service
public class VppUnIntegrationServiceImpl implements VppUnIntegrationService {

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

    private static final int PARTICIPATE_STATUS_ACCEPT = 1;

    @Autowired
    private VppUnPropertiesRegistry propertiesRegistry;
    @Autowired
    private VppUnClient unClient;
    @Autowired
    private VppUnTokenHolder tokenHolder;
    @Autowired
    private VppDrEventMapper eventMapper;
    @Autowired
    private VppDrParticipationMapper participationMapper;
    @Autowired
    private VppSiteMapper siteMapper;
    @Autowired
    private VppResourcePointMapper resourcePointMapper;
    @Autowired
    private VppRegistrationMapper registrationMapper;
    @Autowired
    private VppDrEventIngestService drEventIngestService;
    @Autowired
    private VppUnReportService reportService;

    @Override
    public void loadPersistedRegistrationId() {
        VppUnProperties properties = currentProperties();
        if (!StringUtils.hasText(properties.getDnId()) || StringUtils.hasText(properties.getRegistrationId())) {
            return;
        }
        VppRegistration registration = registrationMapper.selectOne(new LambdaQueryWrapper<VppRegistration>()
                .eq(VppRegistration::getDnId, properties.getDnId())
                .eq(VppRegistration::getTenantId, properties.getTenantId())
                .eq(VppRegistration::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .orderByDesc(VppRegistration::getRegisteredAt)
                .last("LIMIT 1"));
        if (registration != null && StringUtils.hasText(registration.getRegistrationId())) {
            properties.setRegistrationId(registration.getRegistrationId());
            propertiesRegistry.updateRegistrationId(properties.getTenantId(), registration.getRegistrationId());
            log.info("租户 {} 已从数据库加载 registrationID={}", properties.getTenantId(), registration.getRegistrationId());
        }
    }

    @Override
    public Map<String, Object> refreshToken() {
        ensureOutboundEnabled();
        tokenHolder.invalidate();
        VppUnProperties properties = currentProperties();
        Map<String, Object> response = unClient.post("TokenRequest", VppUnMessageBuilder.buildTokenRequest(properties), false);
        tokenHolder.applyTokenResponse(response);
        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> register() {
        ensureOutboundEnabled();
        VppUnProperties properties = currentProperties();
        Map<String, Object> request = VppUnMessageBuilder.buildCreateRegistrationRequest(properties);
        Map<String, Object> response = unClient.post("CreateRegistrationRequest", request, true);
        persistRegistration(response);
        return response;
    }

    @Override
    public Map<String, Object> pollOnce() {
        ensureOutboundEnabled();
        VppUnProperties properties = currentProperties();
        Map<String, Object> response = unClient.post("Poll", VppUnMessageBuilder.buildPollRequest(properties), true);
        handlePollResponse(response);
        return response;
    }

    @Override
    public Map<String, Object> submitParticipation(Long eventId, boolean participate) {
        return submitParticipation(eventId, participate, null);
    }

    @Override
    public Map<String, Object> submitParticipation(Long eventId, boolean participate,
                                                   List<VppDrParticipation> participations) {
        VppUnProperties properties = currentProperties();
        if (!properties.isOutboundActive()) {
            return null;
        }
        VppDrEvent event = requireEvent(eventId);
        String optType = participate ? "optIn" : "optOut";
        List<Map<String, Object>> list = participate
                ? buildListFromParticipations(eventId, false, participations) : null;
        Map<String, Object> request = VppUnMessageBuilder.buildCreateOptRequest(
                event.getEventId(), optType, list, properties);
        Map<String, Object> response = unClient.post("CreateOptRequest", request, true);
        log.info("已向 UN 提交 CreateOptRequest eventId={} optType={} listSize={}",
                event.getEventId(), optType, list != null ? list.size() : 0);
        return response;
    }

    @Override
    public Map<String, Object> submitClearing(Long eventId) {
        VppUnProperties properties = currentProperties();
        if (!properties.isOutboundActive()) {
            return null;
        }
        VppDrEvent event = requireEvent(eventId);
        List<Map<String, Object>> list = buildListFromParticipations(eventId, true, null);
        if (list.isEmpty()) {
            throw new BusinessException("无出清数据可上报 UN");
        }
        Map<String, Object> request = VppUnMessageBuilder.buildCreateCqRequest(
                event.getEventId(), "optIn", list, properties);
        Map<String, Object> response = unClient.post("CreateCqRequest", request, true);
        log.info("已向 UN 提交 CreateCqRequest eventId={}", event.getEventId());
        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> acknowledgeClearing(Long eventId) {
        VppUnProperties properties = currentProperties();
        if (!properties.isOutboundActive()) {
            return null;
        }
        VppDrEvent event = requireEvent(eventId);
        Map<String, Object> request = VppUnMessageBuilder.buildCreateEventResponse(
                event.getEventId(), null, "optIn", properties);
        Map<String, Object> response = unClient.post("CreateEventResponse", request, true);
        drEventIngestService.acknowledgeClearingPublicity(event.getEventId(), request, "Outbound-CreateEventResponse");
        log.info("已向 UN 确认出清公示 eventId={}", event.getEventId());
        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handlePollResponse(Map<String, Object> response) {
        if (response == null || response.isEmpty()) {
            return;
        }
        VppUnProperties properties = currentProperties();
        String root = VppUnPayloadHelper.getString(response, "root");
        if ("DistributeEventRequest".equals(root) || response.containsKey("events")) {
            VppDrEvent event = drEventIngestService.ingestDistributeEvent(response, "Poll-Outbound");
            if (Boolean.TRUE.equals(properties.getAutoAckClearing()) && event != null) {
                maybeAutoAckClearing(event);
            }
            return;
        }
        if ("ReregistrationRequest".equals(root)) {
            log.info("UN 要求重新注册");
            loadPersistedRegistrationId();
            register();
            return;
        }

//        //删除
//        if ("CreateReportRequest".equals(root)) {
//            try {
//                reportService.handleCreateReportRequest(response);
//            } catch (Exception ex) {
//                log.warn("处理 CreateReportRequest 失败: {}", ex.getMessage());
//            }
//        }
    }

    private VppUnProperties currentProperties() {
        return propertiesRegistry.getCurrent();
    }

    private void maybeAutoAckClearing(VppDrEvent event) {
        if (event.getEventStatus() != null && event.getEventStatus() == 1
                && event.getClearedCapacityKw() != null
                && event.getClearedCapacityKw().compareTo(BigDecimal.ZERO) > 0) {
            try {
                acknowledgeClearing(event.getId());
            } catch (Exception ex) {
                log.warn("自动确认出清公示失败 eventId={}: {}", event.getEventId(), ex.getMessage());
            }
        }
    }

    private List<Map<String, Object>> buildListFromParticipations(Long eventId,
                                                                  boolean clearing,
                                                                  List<VppDrParticipation> provided) {
        List<VppDrParticipation> participations = resolveParticipations(eventId, provided);
        List<Map<String, Object>> list = new ArrayList<>();
        for (VppDrParticipation participation : participations) {
            String accountNo = resolveSiteAccountNo(participation);
            if (!StringUtils.hasText(accountNo)) {
                log.warn("参与记录缺少站点电力户号 participationId={} resourceId={} customerId={}",
                        participation.getId(), participation.getResourceId(), participation.getCustomerId());
                continue;
            }
            BigDecimal load = clearing ? participation.getClearedCapacityKw() : participation.getDeclaredCapacityKw();
            if (load == null || load.compareTo(BigDecimal.ZERO) <= 0) {
                continue;
            }
            list.add(VppUnMessageBuilder.buildOptListItem(accountNo, load, "否"));
        }
        return list;
    }

    /** 从站点表 vpp_site.account_no 解析电力户号。 */
    private String resolveSiteAccountNo(VppDrParticipation participation) {
        VppSite site = resolveSite(participation);
        return site != null && StringUtils.hasText(site.getAccountNo()) ? site.getAccountNo().trim() : null;
    }

    private VppSite resolveSite(VppDrParticipation participation) {
        if (participation == null) {
            return null;
        }
        if (participation.getResourceId() != null) {
            VppResourcePoint resource = resourcePointMapper.selectById(participation.getResourceId());
            if (resource != null && resource.getSiteId() != null) {
                return selectActiveSite(resource.getSiteId());
            }
        }
        if (participation.getCustomerId() != null) {
            return siteMapper.selectOne(new LambdaQueryWrapper<VppSite>()
                    .eq(VppSite::getCustomerId, participation.getCustomerId())
                    .eq(VppSite::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                    .last("LIMIT 1"));
        }
        return null;
    }

    private VppSite selectActiveSite(Long siteId) {
        if (siteId == null) {
            return null;
        }
        VppSite site = siteMapper.selectById(siteId);
        if (site == null || VppAuditHelper.isDeleted(site.getDeleteFlag())) {
            return null;
        }
        return site;
    }

    private List<VppDrParticipation> resolveParticipations(Long eventId, List<VppDrParticipation> provided) {
        if (provided != null && !provided.isEmpty()) {
            List<VppDrParticipation> accepted = new ArrayList<>();
            for (VppDrParticipation participation : provided) {
                if (participation == null) {
                    continue;
                }
                if (!eventId.equals(participation.getEventId())) {
                    continue;
                }
                if (participation.getParticipateStatus() != null
                        && participation.getParticipateStatus() != PARTICIPATE_STATUS_ACCEPT) {
                    continue;
                }
                if (VppAuditHelper.isDeleted(participation.getDeleteFlag())) {
                    continue;
                }
                accepted.add(participation);
            }
            if (!accepted.isEmpty()) {
                return accepted;
            }
        }
        return participationMapper.selectList(
                new LambdaQueryWrapper<VppDrParticipation>()
                        .eq(VppDrParticipation::getEventId, eventId)
                        .eq(VppDrParticipation::getParticipateStatus, PARTICIPATE_STATUS_ACCEPT)
                        .eq(VppDrParticipation::getDeleteFlag, VppAuditHelper.NOT_DELETED));
    }

    private void persistRegistration(Map<String, Object> response) {
        VppUnProperties properties = currentProperties();
        String registrationId = VppUnPayloadHelper.getString(response, "registrationID", "registrationId");
        if (!StringUtils.hasText(registrationId)) {
            return;
        }
        properties.setRegistrationId(registrationId);
        propertiesRegistry.updateRegistrationId(properties.getTenantId(), registrationId);

        VppRegistration existing = registrationMapper.selectOne(new LambdaQueryWrapper<VppRegistration>()
                .eq(VppRegistration::getDnId, properties.getDnId())
                .eq(VppRegistration::getTenantId, properties.getTenantId())
                .eq(VppRegistration::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .last("LIMIT 1"));
        if (existing == null) {
            existing = new VppRegistration();
            existing.setDnId(properties.getDnId());
            existing.setRegistrationId(registrationId);
            existing.setRegStatus(1);
            existing.setRegisteredAt(LocalDateTime.now());
            existing.setTenantId(properties.getTenantId());
            VppAuditHelper.fillCreate(existing);
            registrationMapper.insert(existing);
        } else {
            existing.setRegistrationId(registrationId);
            existing.setRegisteredAt(LocalDateTime.now());
            VppAuditHelper.fillUpdate(existing);
            registrationMapper.updateById(existing);
        }
    }

    private VppDrEvent requireEvent(Long eventId) {
        VppDrEvent event = eventMapper.selectById(eventId);
        if (event == null || VppAuditHelper.isDeleted(event.getDeleteFlag())) {
            throw new BusinessException("需求响应事件不存在");
        }
        if (!StringUtils.hasText(event.getEventId())) {
            throw new BusinessException("事件缺少运管平台 eventID");
        }
        return event;
    }

    private void ensureOutboundEnabled() {
        if (!currentProperties().isOutboundActive()) {
            throw new BusinessException("运管平台 outbound 未启用，请在 vpp_tenant_config 中配置 baseUrl 与 outbound_enabled");
        }
    }
}
