package com.cmvr.edge.client.manage;

import cmvr.api.*;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.cmvr.device.domain.DeDeviceTerminalConfig;
import com.cmvr.device.service.IDeDeviceTerminalConfigService;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.*;
import java.util.function.Function;

/**
 * gRPC链接管理
 */
@Service
@RequiredArgsConstructor
public class GrpcServiceManager {

    private final IDeDeviceTerminalConfigService deviceTerminalConfigService;

    @Value("${grpc.client.grpc-server.address}")
    private String DEFAULT_GRPC_ADDRESS;

    // 存储不同 Stub 的工厂
    private final Map<Class<?>, GrpcClientFactory<?>> clientFactories = new ConcurrentHashMap<>();

    // 带 TTL 的通道缓存
    private final GrpcChannelCache grpcChannelCache = new GrpcChannelCache(3 * 60); // 3分钟过期时间

    /**
     * 初始化注册支持的 gRPC Stub
     */
    @PostConstruct
    public void init() {
        // 注册摄像头服务的 Stub
        clientFactories.put(CameraServiceGrpc.CameraServiceBlockingStub.class, new GrpcClientFactory<>(CameraServiceGrpc::newBlockingStub));
        clientFactories.put(CameraServiceGrpc.CameraServiceStub.class, new GrpcClientFactory<>(CameraServiceGrpc::newStub));
        // 注册系统服务的 Stub
        clientFactories.put(SystemServiceGrpc.SystemServiceBlockingStub.class, new GrpcClientFactory<>(SystemServiceGrpc::newBlockingStub));
        // 注册扬声器服务的 Stub
        clientFactories.put(SpeakerServiceGrpc.SpeakerServiceBlockingStub.class, new GrpcClientFactory<>(SpeakerServiceGrpc::newBlockingStub));
        // 注册麦克风服务的 Stub
        clientFactories.put(MicPhoneServiceGrpc.MicPhoneServiceBlockingStub.class, new GrpcClientFactory<>(MicPhoneServiceGrpc::newBlockingStub));
        // 注册机器人头部服务的 Stub
        clientFactories.put(BioHeadServiceGrpc.BioHeadServiceBlockingStub.class, new GrpcClientFactory<>(BioHeadServiceGrpc::newBlockingStub));
        // 注册机器人灵巧手服务的 Stub
        clientFactories.put(DexHandServiceGrpc.DexHandServiceBlockingStub.class, new GrpcClientFactory<>(DexHandServiceGrpc::newBlockingStub));
        clientFactories.put(DexHandServiceGrpc.DexHandServiceStub.class, new GrpcClientFactory<>(DexHandServiceGrpc::newStub));
        // 注册机械臂服务的stub
        clientFactories.put(HumanoidRobotServiceGrpc.HumanoidRobotServiceBlockingStub.class, new GrpcClientFactory<>(HumanoidRobotServiceGrpc::newBlockingStub));
        clientFactories.put(HlcServiceGrpc.HlcServiceBlockingStub.class, new GrpcClientFactory<>(HlcServiceGrpc::newBlockingStub));
        // 注册agv服务的stub
        clientFactories.put(AgvServiceGrpc.AgvServiceBlockingStub.class, new GrpcClientFactory<>(AgvServiceGrpc::newBlockingStub));
    }


    /**
     * 获取 gRPC 客户端 Stub
     */
    @SuppressWarnings("unchecked")
    public <T> T getGrpcClient(String terminalId, Class<T> serviceClass) {
        ManagedChannel channel = grpcChannelCache.get(terminalId, this::createChannel);
        GrpcClientFactory<T> factory = (GrpcClientFactory<T>) clientFactories.get(serviceClass);

        if (factory == null) {
            throw new IllegalArgumentException("未知的 gRPC 服务类型: " + serviceClass);
        }

        return factory.createClient(channel);
    }

    /**
     * 创建gRPC通道
     */
    private ManagedChannel createChannel(String terminalId) {
        String grpcAddress = getGrpcServiceAddress(terminalId);
        return ManagedChannelBuilder.forTarget(grpcAddress)
                .usePlaintext()
                .maxInboundMessageSize(50 * 1024 * 1024) // 50MB
                .build();
    }

    /**
     * 获取终端地址
     */
    private String getGrpcServiceAddress(String terminalId) {
        DeDeviceTerminalConfig terminal = deviceTerminalConfigService.selectDeDeviceTerminalConfigById(terminalId);
        if (ObjUtil.isEmpty(terminal)) {
            return DEFAULT_GRPC_ADDRESS;
        }
        return StrUtil.format("static://{}:{}", terminal.getHost(), terminal.getPort());
    }

    /**
     * 定期清理过期的通道
     */
    @Scheduled(fixedRate = 2 * 60 * 1000)
    public void cleanExpiredChannels() {
        grpcChannelCache.cleanExpiredChannels();
    }

    /**
     * gRPC客户端工厂类
     */
    private static class GrpcClientFactory<T> {
        private final Function<ManagedChannel, T> factory;

        public GrpcClientFactory(Function<ManagedChannel, T> factory) {
            this.factory = factory;
        }

        public T createClient(ManagedChannel channel) {
            return factory.apply(channel);
        }
    }
}
