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.domain.VppCustomer;
import com.usky.vpp.domain.VppDrEvent;
import com.usky.vpp.domain.VppDrParticipation;
import com.usky.vpp.domain.VppRegistration;
import com.usky.vpp.mapper.VppCustomerMapper;
import com.usky.vpp.mapper.VppDrEventMapper;
import com.usky.vpp.mapper.VppDrParticipationMapper;
import com.usky.vpp.mapper.VppRegistrationMapper;
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 javax.annotation.PostConstruct;

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 VppUnProperties properties;
    @Autowired
    private VppUnClient unClient;
    @Autowired
    private VppUnTokenHolder tokenHolder;
    @Autowired
    private VppDrEventMapper eventMapper;
    @Autowired
    private VppDrParticipationMapper participationMapper;
    @Autowired
    private VppCustomerMapper customerMapper;
    @Autowired
    private VppRegistrationMapper registrationMapper;
    @Autowired
    private VppDrEventIngestService drEventIngestService;
    @Autowired
    private VppUnReportService reportService;

    @PostConstruct
    public void loadRegistrationFromDb() {
        if (!StringUtils.hasText(properties.getDnId()) || StringUtils.hasText(properties.getRegistrationId())) {
            return;
        }
        VppRegistration registration = registrationMapper.selectOne(new LambdaQueryWrapper<VppRegistration>()
                .eq(VppRegistration::getDnId, properties.getDnId())
                .eq(VppRegistration::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .orderByDesc(VppRegistration::getRegisteredAt)
                .last("LIMIT 1"));
        if (registration != null && StringUtils.hasText(registration.getRegistrationId())) {
            properties.setRegistrationId(registration.getRegistrationId());
            log.info("已加载 registrationID={}", registration.getRegistrationId());
        }
    }

    @Override
    public Map<String, Object> refreshToken() {
        ensureOutboundEnabled();
        tokenHolder.invalidate();
        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();
        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();
        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) {
        if (!properties.isOutboundActive()) {
            return null;
        }
        VppDrEvent event = requireEvent(eventId);
        String optType = participate ? "optIn" : "optOut";
        List<Map<String, Object>> list = participate ? buildListFromParticipations(eventId, false) : 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={}", event.getEventId(), optType);
        return response;
    }

    @Override
    public Map<String, Object> submitClearing(Long eventId) {
        if (!properties.isOutboundActive()) {
            return null;
        }
        VppDrEvent event = requireEvent(eventId);
        List<Map<String, Object>> list = buildListFromParticipations(eventId, true);
        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) {
        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;
        }
        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 要求重新注册");
            String registrationId = VppUnPayloadHelper.getString(response, "registrationID", "registrationId");
            if (StringUtils.hasText(registrationId)) {
                properties.setRegistrationId(registrationId);
            }
            register();
            return;
        }
        if ("CreateReportRequest".equals(root)) {
            try {
                reportService.handleCreateReportRequest(response);
            } catch (Exception ex) {
                log.warn("处理 CreateReportRequest 失败: {}", ex.getMessage());
            }
        }
    }

    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> participations = participationMapper.selectList(
                new LambdaQueryWrapper<VppDrParticipation>()
                        .eq(VppDrParticipation::getEventId, eventId)
                        .eq(VppDrParticipation::getParticipateStatus, PARTICIPATE_STATUS_ACCEPT)
                        .eq(VppDrParticipation::getDeleteFlag, VppAuditHelper.NOT_DELETED));
        List<Map<String, Object>> list = new ArrayList<>();
        for (VppDrParticipation participation : participations) {
            VppCustomer customer = customerMapper.selectById(participation.getCustomerId());
            if (customer == null || !StringUtils.hasText(customer.getAccountNo())) {
                log.warn("参与记录缺少电力户号 customerId={}", participation.getCustomerId());
                continue;
            }
            BigDecimal load = clearing ? participation.getClearedCapacityKw() : participation.getDeclaredCapacityKw();
            if (load == null || load.compareTo(BigDecimal.ZERO) <= 0) {
                continue;
            }
            list.add(VppUnMessageBuilder.buildOptListItem(customer.getAccountNo(), load, "否"));
        }
        return list;
    }

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

        VppRegistration existing = registrationMapper.selectOne(new LambdaQueryWrapper<VppRegistration>()
                .eq(VppRegistration::getDnId, properties.getDnId())
                .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());
            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 (!properties.isOutboundActive()) {
            throw new BusinessException("运管平台 outbound 未启用，请配置 vpp.un.baseUrl 与 outbound-enabled");
        }
    }
}
