package com.cmvr.edge.client.service.impl;

import cmvr.api.AgvCommand;
import cmvr.api.AgvServiceGrpc;
import cmvr.api.Common;
import cmvr.msgs.Agv;
import cn.hutool.core.util.StrUtil;
import com.cmvr.common.exception.GlobalException;
import com.cmvr.edge.client.manage.GrpcServiceManager;
import com.cmvr.edge.client.model.EdgeCommonVO;
import com.cmvr.edge.client.service.EdgeAgvService;
import com.cmvr.edge.client.utils.EdgeCommonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * AGV服务实现类
 * 
 * @author cmvr-iot
 * @since 2026-07-02
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EdgeAgvServiceImpl implements EdgeAgvService {

    private final GrpcServiceManager grpcServiceManager;

    @Override
    public Agv.AgvRuntimeState getRuntimeState(EdgeCommonVO edgeCommonVO) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvRuntimeStateCommand.Request request = AgvCommand.AgvRuntimeStateCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .build();
        return executeGrpcCall(() -> stub.getRuntimeState(request)).getState();
    }

    @Override
    public Agv.AgvNavigationStatus getNavigationStatus(EdgeCommonVO edgeCommonVO) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvNavigationStatusCommand.Request request = AgvCommand.AgvNavigationStatusCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .build();
        return executeGrpcCall(() -> stub.getNavigationStatus(request)).getStatus();
    }

    @Override
    public void emergencyStop(EdgeCommonVO edgeCommonVO) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
        executeGrpcCall(() -> stub.emergencyStop(request));
    }

    @Override
    public void clearFault(EdgeCommonVO edgeCommonVO) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
        executeGrpcCall(() -> stub.clearFault(request));
    }

    @Override
    public void navigateToPose(EdgeCommonVO edgeCommonVO, Agv.AgvPose2d pose) {
        if (pose == null) {
            throw new GlobalException("目标位姿不能为空");
        }
        
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvNavigateToPoseCommand.Request request = AgvCommand.AgvNavigateToPoseCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .setPose(pose)
            .build();
        executeGrpcCall(() -> stub.navigateToPose(request));
    }

    @Override
    public void navigateToStation(EdgeCommonVO edgeCommonVO, String stationId) {
        if (StrUtil.isBlank(stationId)) {
            throw new GlobalException("站点ID不能为空");
        }
        
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvNavigateToStationCommand.Request request = AgvCommand.AgvNavigateToStationCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .setStationId(stationId)
            .build();
        executeGrpcCall(() -> stub.navigateToStation(request));
    }

    @Override
    public void followPath(EdgeCommonVO edgeCommonVO, List<Agv.AgvPathSegment> pathSegments) {
        if (pathSegments == null || pathSegments.isEmpty()) {
            throw new GlobalException("路径段不能为空");
        }
        
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvFollowPathCommand.Request request = AgvCommand.AgvFollowPathCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .addAllPath(pathSegments)
            .build();
        executeGrpcCall(() -> stub.followPath(request));
    }

    @Override
    public void pauseNavigation(EdgeCommonVO edgeCommonVO) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
        executeGrpcCall(() -> stub.pauseNavigation(request));
    }

    @Override
    public void resumeNavigation(EdgeCommonVO edgeCommonVO) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
        executeGrpcCall(() -> stub.resumeNavigation(request));
    }

    @Override
    public void cancelNavigation(EdgeCommonVO edgeCommonVO) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
        executeGrpcCall(() -> stub.cancelNavigation(request));
    }

    @Override
    public void setVelocity(EdgeCommonVO edgeCommonVO, Agv.AgvVelocity velocity) {
        if (velocity == null) {
            throw new GlobalException("速度不能为空");
        }
        
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvSetVelocityCommand.Request request = AgvCommand.AgvSetVelocityCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .setVelocity(velocity)
            .build();
        executeGrpcCall(() -> stub.setVelocity(request));
    }

    @Override
    public void stopVelocityControl(EdgeCommonVO edgeCommonVO) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
        executeGrpcCall(() -> stub.stopVelocityControl(request));
    }

    @Override
    public List<String> listMaps(EdgeCommonVO edgeCommonVO) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvListMapsCommand.Request request = AgvCommand.AgvListMapsCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .build();
        return executeGrpcCall(() -> stub.listMaps(request)).getMapsList();
    }

    @Override
    public List<Agv.AgvStation> listStations(EdgeCommonVO edgeCommonVO) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvListStationsCommand.Request request = AgvCommand.AgvListStationsCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .build();
        return executeGrpcCall(() -> stub.listStations(request)).getStationsList();
    }

    @Override
    public void switchMap(EdgeCommonVO edgeCommonVO, String mapName) {
        if (StrUtil.isBlank(mapName)) {
            throw new GlobalException("地图名称不能为空");
        }
        
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvMapCommand.Request request = AgvCommand.AgvMapCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .setMapName(mapName)
            .build();
        executeGrpcCall(() -> stub.switchMap(request));
    }

    @Override
    public void uploadMap(EdgeCommonVO edgeCommonVO, String mapName, String content) {
        if (StrUtil.isBlank(mapName)) {
            throw new GlobalException("地图名称不能为空");
        }
        if (StrUtil.isBlank(content)) {
            throw new GlobalException("地图内容不能为空");
        }
        
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvMapCommand.Request request = AgvCommand.AgvMapCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .setMapName(mapName)
            .setContent(content)
            .build();
        executeGrpcCall(() -> stub.uploadMap(request));
    }

    @Override
    public String downloadMap(EdgeCommonVO edgeCommonVO, String mapName) {
        if (StrUtil.isBlank(mapName)) {
            throw new GlobalException("地图名称不能为空");
        }
        
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvMapCommand.Request request = AgvCommand.AgvMapCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .setMapName(mapName)
            .build();
        return executeGrpcCall(() -> stub.downloadMap(request)).getContent();
    }

    @Override
    public String startMapping(EdgeCommonVO edgeCommonVO, Agv.AgvMapDimension dimension, String mapName, boolean realTime) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        AgvCommand.AgvStartMappingCommand.Request.Builder requestBuilder = AgvCommand.AgvStartMappingCommand.Request.newBuilder()
            .setHeader(EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId()))
            .setDimension(dimension != null ? dimension : Agv.AgvMapDimension.AGV_MAP_DIMENSION_UNSPECIFIED)
            .setRealTime(realTime);
        
        if (StrUtil.isNotBlank(mapName)) {
            requestBuilder.setMapName(mapName);
        }
        
        AgvCommand.AgvStartMappingCommand.Request request = requestBuilder.build();
        return executeGrpcCall(() -> stub.startMapping(request)).getSessionId();
    }

    @Override
    public void stopMapping(EdgeCommonVO edgeCommonVO) {
        AgvServiceGrpc.AgvServiceBlockingStub stub = grpcServiceManager.getGrpcClient(
            edgeCommonVO.getTerminalId(), AgvServiceGrpc.AgvServiceBlockingStub.class);
        Common.CommandHeader.Request request = EdgeCommonUtil.buildRequest(edgeCommonVO.getDeviceId());
        executeGrpcCall(() -> stub.stopMapping(request));
    }

    /**
     * 执行gRPC调用并处理异常
     *
     * @param call gRPC调用
     * @param <T> 返回类型
     * @return 调用结果
     */
    private <T> T executeGrpcCall(java.util.function.Supplier<T> call) {
        try {
            return call.get();
        } catch (Exception e) {
            log.error("AGV gRPC调用失败", e);
            throw new GlobalException("AGV通信失败: " + e.getMessage());
        }
    }
}
