using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
using Microsoft.EntityFrameworkCore;
using RobotNet.RobotManager.Controllers;
using RobotNet.RobotManager.Data;
using RobotNet.RobotManager.Services;
using RobotNet.RobotManager.Services.OpenACS;
using RobotNet.RobotShares.Models;
using RobotNet.Shares;

namespace RobotNet.RobotManager.Hubs;

[Authorize]
public class RobotManagerHub(RobotEditorDbContext RobotDb, MapManager MapManager, Services.RobotManager RobotManager, TrafficACS TrafficACS, ILogger<RobotManagerController> Logger) : Hub
{
    public async Task<MessageResult> MoveToNode(RobotMoveToNodeModel model)
    {
        try
        {
            if (string.IsNullOrEmpty(model.NodeName)) return new(false, "NodeName cannot be empty..");

            var robot = await RobotDb.Robots.FirstOrDefaultAsync(r => r.RobotId == model.RobotId);
            if (robot is null) return new(false, "RobotId does not exist.");

            var robotController = RobotManager[robot.RobotId];
            if (robotController is null || !robotController.IsOnline) return new(false, "The robot is not online.");

            var map = await MapManager.GetMapData(robot.MapId);
            if (!map.IsSuccess) return new(false, map.Message);
            if (map is null || map.Data is null) return new(false, "The robot has not been assigned a map.");

            var node = map.Data.Nodes.FirstOrDefault(n => n.Name == model.NodeName && n.MapId == map.Data.Id);
            if (node is null) return new(false, "This Node does not exist.");

            if (robotController.IsWorking) return new(false, "The robot is busy.");

            var move = await robotController.MoveToNode(node.Name, model.Actions, model.OverrideLastAngle ? model.LastAngle : null);
            if (move.IsSuccess)
            {
                robotController.Log($"RobotManager API Controller Log: Goi Robot {model.RobotId} di chuyển tới node {model.NodeName} thành công ");
                return new(true);
            }
            robotController.Log($"RobotManager API Controller Log: Goi Robot {model.RobotId} di chuyển tới node {model.NodeName} không thành công thành công do {move.Message}");
            return new(false, move.Message);
        }
        catch (Exception ex)
        {
            Logger.LogError("RobotManager API Controller Log: Goi MoveToNode Robot {RobotId} di chuyển tới node {NodeName} xảy ra lỗi: {Message}", model.RobotId, model.NodeName, ex.Message);
            return new(false, "An error occurred.");
        }
    }

    public async Task<MessageResult> MoveStraight(RobotMoveStraightModel model)
    {
        try
        {
            var robot = await RobotDb.Robots.FirstOrDefaultAsync(r => r.RobotId == model.RobotId);
            if (robot is null) return new(false, "RobotId does not exist.");

            var robotController = RobotManager[robot.RobotId];
            if (robotController is null || !robotController.IsOnline) return new(false, "The robot is not online.");
            if (robotController.IsWorking) return new(false, "The robot is busy.");

            var move = robotController.MoveStraight(model.X, model.Y);
            if (move.IsSuccess)
            {
                robotController.Log($"RobotManager API Controller Log: Goi Robot {model.RobotId} di chuyển tới tọa độ [{model.X} - {model.Y}] thành công ");
                return new(true);
            }
            robotController.Log($"RobotManager API Controller Log: Goi Robot {model.RobotId} di chuyển tới tọa độ [{model.X} - {model.Y}] không thành công thành công do {move.Message}");
            return new(false, "Request failed.");
        }
        catch (Exception ex)
        {
            Logger.LogError("RobotManager API Controller Log: Goi Rotate Robot {RobotId} di chuyển tới tọa độ [{model.X} - {model.Y}] xảy ra lỗi: {Message}", model.RobotId, model.X, model.Y, ex.Message);
            return new(false, "An error occurred.");
        }
    }

    public async Task<MessageResult> Rotate(RobotRotateModel model)
    {
        try
        {
            var robot = await RobotDb.Robots.FirstOrDefaultAsync(r => r.RobotId == model.RobotId);
            if (robot is null) return new(false, "RobotId does not exist.");

            var robotController = RobotManager[robot.RobotId];
            if (robotController is null || !robotController.IsOnline) return new(false, "The robot is not online.");
            if (robotController.IsWorking) return new(false, "The robot is busy.");

            var move = robotController.Rotate(model.Angle);
            if (move.IsSuccess)
            {
                robotController.Log($"RobotManager API Controller Log: Goi Robot {model.RobotId} quay tới góc {model.Angle} thành công ");
                return new(true);
            }
            robotController.Log($"RobotManager API Controller Log: Goi Robot {model.RobotId} quay tới góc {model.Angle} không thành công thành công do {move.Message}");
            return new(false, "Request failed.");
        }
        catch (Exception ex)
        {
            Logger.LogError("RobotManager API Controller Log: Goi Rotate Robot {RobotId} quay tới góc {model.Angle} xảy ra lỗi: {Message}", model.RobotId, model.Angle, ex.Message);
            return new(false, "An error occurred.");
        }
    }

    public async Task<MessageResult> CancelOrder(string robotId)
    {
        try
        {
            var robot = await RobotDb.Robots.FirstOrDefaultAsync(r => r.RobotId == robotId);
            if (robot is null) return new(false, "RobotId does not exist.");

            var robotController = RobotManager[robot.RobotId];
            if (robotController is null || !robotController.IsOnline) return new(false, "The robot is not online.");

            var cancel = await robotController.CancelOrder();
            if (cancel.IsSuccess)
            {
                robotController.Log($"RobotManager API Controller Log: Hủy bỏ nhiệm vụ của Robot {robotId} thành công ");
                return new(true);
            }
            robotController.Log($"RobotManager API Controller Log: Hủy bỏ nhiệm vụ của Robot {robotId} không thành công do {cancel.Message}");
            return new(false, "Request failed.");
        }
        catch (Exception ex)
        {
            Logger.LogError("RobotManager API Controller Log: Goi Cancel Order Robot {RobotId} xảy ra lỗi: {Message}", robotId, ex.Message);
            return new(false, "An error occurred.");
        }
    }

    public async Task<MessageResult> CancelAction(string robotId)
    {
        try
        {
            var robot = await RobotDb.Robots.FirstOrDefaultAsync(r => r.RobotId == robotId);
            if (robot is null) return new(false, "RobotId does not exist.");

            var robotController = RobotManager[robot.RobotId];
            if (robotController is null || !robotController.IsOnline) return new(false, "The robot is not online.");

            var cancel = await robotController.CancelAction();
            if (cancel.IsSuccess)
            {
                robotController.Log($"RobotManager API Controller Log: Hủy bỏ nhiệm vụ của Robot {robotId} thành công ");
                return new(true);
            }
            robotController.Log($"RobotManager API Controller Log: Hủy bỏ nhiệm vụ của Robot {robotId} không thành công do {cancel.Message}");
            return new(false, "Request failed.");
        }
        catch (Exception ex)
        {
            Logger.LogError("RobotManager API Controller Log: Goi Cancel Order Robot {RobotId} xảy ra lỗi: {Message}", robotId, ex.Message);
            return new(false, "An error occurred.");
        }
    }

    public async Task<MessageResult<string>> InstantAction(RobotInstantActionModel model)
    {
        try
        {
            var robot = await RobotDb.Robots.FirstOrDefaultAsync(r => r.RobotId == model.RobotId);
            if (robot is null) return new(false, "RobotId does not exist.");

            var robotController = RobotManager[robot.RobotId];
            if (robotController is null || !robotController.IsOnline) return new(false, "The robot is not online.");

            var instantAction = await robotController.InstantAction(model.Action, false);
            if (instantAction.IsSuccess)
            {
                robotController.Log($"RobotManager API Controller Log: Gửi Action Robot {model.RobotId} thành công ");
                return instantAction;
            }
            robotController.Log($"RobotManager API Controller Log: Gửi Action Robot {model.RobotId} không thành công do {instantAction.Message}");
            return new(false, "Request failed.");
        }
        catch (Exception ex)
        {
            Logger.LogError("RobotManager API Controller Log: Goi InstantAction Robot {RobotId}, Action type {action} xảy ra lỗi: {Message}", model.RobotId, model.Action.ActionType, ex.Message);
            return new(false, "An error occurred.");
        }
    }

    public async Task<MessageResult<RobotStateModel>> GetState(string robotId)
    {
        try
        {
            var robot = await RobotDb.Robots.FirstOrDefaultAsync(r => r.RobotId == robotId);
            if (robot is null) return new(false, "RobotId does not exist.");

            var robotController = RobotManager[robot.RobotId];
            if (robotController is null) return new(true, "")
            {
                Data = new()
                {
                    RobotId = robotId,
                    IsOnline = false,
                    MapId = robot.MapId,
                }
            };

            return new(true)
            {
                Data = new()
                {
                    RobotId = robotId,
                    MapId = robot.MapId,
                    IsOnline = robotController.IsOnline,
                    State = robotController.State,
                    OrderState = robotController.OrderState,
                    NewBaseRequest = robotController.StateMsg.NewBaseRequest,
                    NodeStates = [.. robotController.StateMsg.NodeStates],
                    EdgeStates = [.. robotController.StateMsg.EdgeStates],
                    Loads = [.. robotController.StateMsg.Loads],
                    ActionStates = robotController.ActionStates,
                    BatteryState = robotController.StateMsg.BatteryState,
                    Errors = [.. robotController.StateMsg.Errors],
                    Information = [.. robotController.StateMsg.Information],
                    SafetyState = robotController.StateMsg.SafetyState,
                    AgvPosition = robotController.VisualizationMsg.AgvPosition,
                    Velocity = robotController.VisualizationMsg.Velocity,
                }
            };
        }
        catch (Exception ex)
        {
            Logger.LogError("RobotManager API Controller Log: Goi GetState Robot {RobotId} xảy ra lỗi: {Message}", robotId, ex.Message);
            return new(false, "An error occurred.");
        }
    }

    public async Task<bool> RequestACSIn(string robotId, string id)
    {
        var result = await TrafficACS.RequestIn(robotId, id);
        return result.Data;
    }

    public async Task<bool> RequestACSOut(string robotId, string id)
    {
        var result = await TrafficACS.RequestOut(robotId, id);
        return result.Data;
    }
}
