using RobotNet.Script.Expressions;
using System.Linq.Expressions;

namespace RobotNet.Script;

/// <summary>
/// Service điểu khiển robot trong hệ thống RobotNet.
/// </summary>
public interface IRobot
{
    /// <summary>
    /// Di chuyển robot đến một nút trong bản đồ với action kết thúc.
    /// </summary>
    /// <param name="nodeName"></param>
    /// <param name="actions"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<RobotResult> Move(string nodeName, IDictionary<string, IEnumerable<RobotAction>> actions, CancellationToken cancellationToken);


    /// <summary>
    /// Di chuyển robot đến một nút trong bản đồ với action kết thúc.
    /// </summary>
    /// <param name="nodeName"></param>
    /// <param name="actions"></param>
    /// <param name="lastAngle"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<RobotResult> Move(string nodeName, IDictionary<string, IEnumerable<RobotAction>> actions, double lastAngle, CancellationToken cancellationToken);

    /// <summary>
    /// Di chuyển robot đến một nút trong bản đồ với action kết thúc.
    /// </summary>
    /// <param name="nodeName"></param>
    /// <param name="lastActions"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<RobotResult> Move(string nodeName, IEnumerable<RobotAction> lastActions, CancellationToken cancellationToken);

    /// <summary>
    /// Di chuyển robot đến một nút trong bản đồ với action kết thúc.
    /// </summary>
    /// <param name="nodeName"></param>
    /// <param name="lastActions"></param>
    /// <param name="lastAngle"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<RobotResult> Move(string nodeName, IEnumerable<RobotAction> lastActions, double lastAngle, CancellationToken cancellationToken);

    /// <summary>
    /// Di chuyển robot đến một nút trong bản đồ mà không cần action kết thúc.
    /// </summary>
    /// <param name="nodeName"></param>
    /// <param name="lastAngle"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<RobotResult> Move(string nodeName, double lastAngle, CancellationToken cancellationToken);

    /// <summary>
    /// Di chuyển robot đến một nút trong bản đồ mà không cần action kết thúc.
    /// </summary>
    /// <param name="nodeName"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<RobotResult> Move(string nodeName, CancellationToken cancellationToken);

    /// <summary>
    /// Hủy bỏ hành động di chuyển hiện tại của robot, nếu có.
    /// </summary>
    /// <returns></returns>
    Task AbortMovement();

    /// <summary>
    /// Thực hiện một hành động ngay lập tức trên robot mà không cần chờ đợi.
    /// </summary>
    /// <param name="action"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<RobotResult> Execute(RobotAction action, CancellationToken cancellationToken);


    /// <summary>
    /// Lấy trạng thái của robot
    /// </summary>
    /// <returns></returns>
    Task<RobotState> GetState();

    /// <summary>
    /// Waits for the system to reach a ready state.
    /// </summary>
    /// <param name="cancellationToken">A token to monitor for cancellation requests. If the token is canceled, the operation will be aborted.</param>
    /// <returns>A task that represents the asynchronous operation. The task result is <see langword="true"/> if the system
    /// reaches a ready state; otherwise, <see langword="false"/> if the operation is canceled or the system fails to
    /// become ready.</returns>
    Task<bool> WaitForReady(CancellationToken cancellationToken);

    /// <summary>
    /// 
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    Task<bool> RequestACSIn(string id);

    /// <summary>
    /// 
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    Task<bool> RequestACSOut(string id);

    /// <summary>
    /// Trả về danh sách các tải trọng hiện tại của robot, bao gồm ID, loại, vị trí và trọng lượng.
    /// </summary>
    /// <returns></returns>
    Task<RobotLoad[]> GetLoads();

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    Task<bool> CancelOrder();

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    Task<bool> CancelAction();

    /// <summary>
    /// Chức năng di chuyển robot giả lập theo tọa độ (x, y) trong không gian 2D.
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<RobotResult> SimMoveStraight(double x, double y, CancellationToken cancellationToken);

    /// <summary>
    /// Chức năng xoay robot giả lập theo một góc nhất định (đơn vị: độ).
    /// </summary>
    /// <param name="angle"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    Task<RobotResult> SimRotate(double angle, CancellationToken cancellationToken);
}

/// <summary>
/// Service quản lý các robot trong hệ thống RobotNet.
/// </summary>
public interface IRobotManager
{
    /// <summary>
    /// Trả về đối tượng điểu khiển robot theo ID.
    /// </summary>
    /// <param name="robotId"></param>
    /// <returns></returns>
    Task<IRobot?> GetRobotById(string robotId);

    /// <summary>
    /// Lấy trạng thái của một robot theo ID.
    /// </summary>
    /// <param name="robotId"></param>
    /// <returns></returns>
    Task<RobotState> GetRobotState(string robotId);

    /// <summary>
    /// Tìm kiếm các robot trong bản đồ theo tên và mô hình.
    /// </summary>
    /// <param name="map"></param>
    /// <param name="model"></param>
    /// <returns></returns>
    Task<IEnumerable<string>> SearchRobots(string map, string model);

    /// <summary>
    /// Tìm kiếm các robot trong bản đồ theo tên và mô hình.
    /// </summary>
    /// <param name="map"></param>
    /// <param name="model"></param>
    /// <param name="expr"></param>
    /// <returns></returns>
    Task<IEnumerable<string>> SearchRobots(string map, string model, Expression<Func<Expressions.RobotState, bool>> expr);
}

/// <summary>
/// Regulates if the action is allowed to be executed during movement and/or parallel to other actions.
/// </summary>
public enum BlockingType
{
    /// <summary>
    /// Action can happen in parallel with others, including movement.
    /// </summary>
    NONE,

    /// <summary>
    /// Action can happen simultaneously with others, but not while moving.
    /// </summary>
    SOFT,

    /// <summary>
    /// No other actions can be performed while this action is running.
    /// </summary>
    HARD
}

/// <summary>
/// Mô tả một hành động của robot.
/// </summary>
/// <param name="ActionType"></param>
/// <param name="BlockingType"></param>
public record RobotAction(string ActionType, BlockingType BlockingType)
{
    /// <summary>
    /// Danh sách các tham số của hành động robot.
    /// </summary>
    public IDictionary<string, string>? Parameters { get; set; }
}

/// <summary>
/// Dữ liệu trả về từ các hành động của robot, bao gồm thông tin về thành công hay thất bại và thông điệp mô tả.
/// </summary>
/// <param name="IsSuccess"></param>
/// <param name="Message"></param>
public record RobotResult(bool IsSuccess, string Message);

/// <summary>
/// Thông tin về tải trọng của robot, bao gồm ID, loại, vị trí và trọng lượng.
/// </summary>
/// <param name="Id"></param>
/// <param name="Type"></param>
/// <param name="Position"></param>
/// <param name="Weight"></param>
public record RobotLoad(string Id, string Type, string Position, double Weight);
