package com.usky.vpp.config;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.usky.common.core.exception.BusinessException;
import com.usky.vpp.domain.VppRegistration;
import com.usky.vpp.domain.VppTenantConfig;
import com.usky.vpp.mapper.VppRegistrationMapper;
import com.usky.vpp.mapper.VppTenantConfigMapper;
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.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 租户 UN 配置全局内存缓存，key=tenantId，value=VppUnProperties
 */
@Component
public class VppUnPropertiesRegistry {

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

    private final ConcurrentHashMap<Integer, VppUnProperties> cache = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, Integer> dnIdToTenantId = new ConcurrentHashMap<>();

    @Autowired
    private VppTenantConfigMapper tenantConfigMapper;

    @Autowired
    private VppRegistrationMapper registrationMapper;

    public void refreshAll() {
        List<VppTenantConfig> configs = tenantConfigMapper.selectList(new LambdaQueryWrapper<>());
        if (CollectionUtils.isEmpty(configs)) {
            cache.clear();
            dnIdToTenantId.clear();
            log.warn("vpp_tenant_config 无配置记录，UN 对接配置缓存为空");
            return;
        }

        Map<Integer, VppUnProperties> nextCache = new ConcurrentHashMap<>();
        Map<String, Integer> nextDnIndex = new ConcurrentHashMap<>();
        for (VppTenantConfig config : configs) {
            if (config.getTenantId() == null) {
                continue;
            }
            VppUnProperties properties = toProperties(config);
            enrichRegistrationId(properties);
            nextCache.put(config.getTenantId(), properties);
            if (StringUtils.hasText(config.getDnId())) {
                nextDnIndex.put(config.getDnId(), config.getTenantId());
            }
        }
        cache.clear();
        cache.putAll(nextCache);
        dnIdToTenantId.clear();
        dnIdToTenantId.putAll(nextDnIndex);
        log.info("已加载 {} 条租户 UN 配置至内存", cache.size());
    }

    public VppUnProperties get(Integer tenantId) {
        if (tenantId == null) {
            return null;
        }
        return cache.get(tenantId);
    }

    public VppUnProperties require(Integer tenantId) {
        VppUnProperties properties = get(tenantId);
        if (properties == null) {
            throw new BusinessException("租户 " + tenantId + " 未配置运管平台 UN 对接信息");
        }
        return properties;
    }

    public VppUnProperties getCurrent() {
        // 定时任务：runWithTenant 传入的 tenantId；接口调用：SecurityUtils.getTenantId()
        return require(VppUnTenantContext.resolveTenantId());
    }

    public VppUnProperties getByDnId(String dnId) {
        if (!StringUtils.hasText(dnId)) {
            return null;
        }
        Integer tenantId = dnIdToTenantId.get(dnId);
        return tenantId != null ? get(tenantId) : null;
    }

    public Collection<VppUnProperties> getAll() {
        return Collections.unmodifiableCollection(cache.values());
    }

    public boolean hasCryptoEnabledTenant() {
        return cache.values().stream().anyMatch(this::isCryptoActive);
    }

    private boolean isCryptoActive(VppUnProperties properties) {
        return Boolean.TRUE.equals(properties.getCryptoEnabled())
                && StringUtils.hasText(properties.getUnPublicKey())
                && StringUtils.hasText(properties.getDnPrivateKey());
    }

    public void updateRegistrationId(Integer tenantId, String registrationId) {
        VppUnProperties properties = get(tenantId);
        if (properties != null) {
            properties.setRegistrationId(registrationId);
        }
    }

    public void updateToken(Integer tenantId, String token) {
        VppUnProperties properties = get(tenantId);
        if (properties != null) {
            properties.setToken(token);
        }
    }

    private VppUnProperties toProperties(VppTenantConfig config) {
        VppUnProperties properties = new VppUnProperties();
        properties.setTenantId(config.getTenantId());
        properties.setDnId(config.getDnId());
        properties.setDnName(config.getDnName());
        properties.setBaseUrl(config.getBaseUrl());
        properties.setTransportAddress(config.getTransportAddress());
        properties.setUnPublicKey(config.getUnPublicKey());
        properties.setDnPublicKey(config.getDnPublicKey());
        properties.setDnPrivateKey(config.getDnPrivateKey());
        properties.setToken(config.getToken());
        properties.setPollIntervalSec(config.getPollIntervalSec() != null ? config.getPollIntervalSec() : 10);
        properties.setOutboundEnabled(config.getOutboundEnabled());
        properties.setPollEnabled(config.getPollEnabled());
        properties.setCryptoEnabled(config.getCryptoEnabled());
        properties.setPriceDownCoeff(StringUtils.hasText(config.getPriceDownCoeff()) ? config.getPriceDownCoeff() : "0.8");
        properties.setAutoAckClearing(config.getAutoAckClearing());
        properties.setAutoRegisterOnStartup(config.getAutoRegisterOnStartup());
        properties.setTokenTtlMinutes(25);
        properties.setConnectTimeoutMs(10000);
        properties.setReadTimeoutMs(30000);
        return properties;
    }

    private void enrichRegistrationId(VppUnProperties properties) {
        if (!StringUtils.hasText(properties.getDnId())) {
            return;
        }
        LambdaQueryWrapper<VppRegistration> wrapper = new LambdaQueryWrapper<VppRegistration>()
                .eq(VppRegistration::getDnId, properties.getDnId())
                .eq(VppRegistration::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .orderByDesc(VppRegistration::getRegisteredAt)
                .last("LIMIT 1");
        if (properties.getTenantId() != null) {
            wrapper.eq(VppRegistration::getTenantId, properties.getTenantId());
        }
        VppRegistration registration = registrationMapper.selectOne(wrapper);
        if (registration != null && StringUtils.hasText(registration.getRegistrationId())) {
            properties.setRegistrationId(registration.getRegistrationId());
        }
    }
}
