namespace SpaceGame.Api.Shared.Runtime;

public enum SpatialNodeKind
{
    Star,
    Planet,
    Moon,
    LagrangePoint,
}

public enum WorkStatus
{
    Pending,
    Active,
    Blocked,
    Completed,
    Failed,
    Interrupted,
}

public enum OrderStatus
{
    Queued,
    Active,
    Completed,
    Cancelled,
    Failed,
    Interrupted,
}

public enum ShipOrderSourceKind
{
    Player,
    Behavior,
    Commander,
}

public enum AiPlanStatus
{
    Planned,
    Running,
    Blocked,
    Completed,
    Failed,
    Interrupted,
}

public enum AiPlanStepStatus
{
    Planned,
    Running,
    Blocked,
    Completed,
    Failed,
    Interrupted,
}

public enum AiPlanSourceKind
{
    Rule,
    Order,
    DefaultBehavior,
}

public enum ShipState
{
    Idle,
    Arriving,
    LocalFlight,
    SpoolingWarp,
    Warping,
    SpoolingFtl,
    Ftl,
    CargoFull,
    MiningApproach,
    Mining,
    NodeDepleted,
    AwaitingDock,
    DockingApproach,
    Docking,
    Docked,
    Transferring,
    Loading,
    Unloading,
    WaitingMaterials,
    ConstructionBlocked,
    Constructing,
    DeliveringConstruction,
    Blocked,
    Undocking,
    EngagingTarget,
    HoldingPosition,
    Fleeing,
}

public enum SpaceLayerKind
{
    UniverseSpace,
    GalaxySpace,
    SystemSpace,
    LocalSpace,
}

public enum MovementRegimeKind
{
    LocalFlight,
    Warp,
    StargateTransit,
    FtlTransit,
}

public enum ModuleType
{
    BuildModule,
    ConnectionModule,
    DefenceModule,
    DockArea,
    Habitation,
    Pier,
    ProcessingModule,
    Production,
    Storage,
}

public enum StorageKind
{
    Condensate,
    Container,
    Liquid,
    Solid,
}

public static class CommanderKind
{
    public const string Faction = "faction";
    public const string Station = "station";
    public const string Ship = "ship";
    public const string Fleet = "fleet";
    public const string Sector = "sector";
    public const string TaskGroup = "task-group";
}

public static class ShipTaskKinds
{
    public const string HoldPosition = "hold-position";
    public const string Travel = "travel";
    public const string FollowTarget = "follow-target";
    public const string MineNode = "mine-node";
    public const string Dock = "dock";
    public const string Undock = "undock";
    public const string LoadCargo = "load-cargo";
    public const string UnloadCargo = "unload-cargo";
    public const string TransferCargoToShip = "transfer-cargo-to-ship";
    public const string SalvageWreck = "salvage-wreck";
    public const string DeliverConstruction = "deliver-construction";
    public const string ConstructModule = "construct-module";
    public const string BuildConstructionSite = "build-construction-site";
    public const string AttackTarget = "attack-target";
    public const string Flee = "flee";
    public const string Wait = "wait";
}

public static class ShipOrderKinds
{
    public const string Move = "move";
    public const string DockAtStation = "dock-at-station";
    public const string DockAndWait = "dock-and-wait";
    public const string FlyAndWait = "fly-and-wait";
    public const string FlyToObject = "fly-to-object";
    public const string FollowShip = "follow-ship";
    public const string TradeRoute = "trade-route";
    public const string MineAndDeliver = "mine-and-deliver";
    public const string BuildAtSite = "build-at-site";
    public const string AttackTarget = "attack-target";
    public const string HoldPosition = "hold-position";
    public const string MineLocal = "mine-local";
    public const string MineAndDeliverRun = "mine-and-deliver-run";
    public const string SellMinedCargo = "sell-mined-cargo";
    public const string SupplyFleetRun = "supply-fleet-run";
    public const string SalvageRun = "salvage-run";
    public const string RepeatOrders = "repeat-orders";
    public const string Flee = "flee";
}

public static class ClaimStateKinds
{
    public const string Placed = "placed";
    public const string Activating = "activating";
    public const string Active = "active";
    public const string Destroyed = "destroyed";
}

public static class ConstructionSiteStateKinds
{
    public const string Planned = "planned";
    public const string Active = "active";
    public const string Paused = "paused";
    public const string Completed = "completed";
    public const string Destroyed = "destroyed";
}

public static class MarketOrderKinds
{
    public const string Buy = "buy";
    public const string Sell = "sell";
}

public static class MarketOrderStateKinds
{
    public const string Open = "open";
    public const string PartiallyFilled = "partially-filled";
    public const string Filled = "filled";
    public const string Cancelled = "cancelled";
}

public static class SimulationEnumMappings
{
    public static string ToDataValue(this ModuleType moduleType) => moduleType switch
    {
        ModuleType.BuildModule => "buildmodule",
        ModuleType.ConnectionModule => "connectionmodule",
        ModuleType.DefenceModule => "defencemodule",
        ModuleType.DockArea => "dockarea",
        ModuleType.Habitation => "habitation",
        ModuleType.Pier => "pier",
        ModuleType.ProcessingModule => "processingmodule",
        ModuleType.Production => "production",
        ModuleType.Storage => "storage",
        _ => throw new ArgumentOutOfRangeException(nameof(moduleType), moduleType, null),
    };

    public static ModuleType ToModuleType(this string value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentOutOfRangeException(nameof(value), value, "Module type is required.");
        }

        return value.Trim().ToLowerInvariant() switch
        {
            "buildmodule" => ModuleType.BuildModule,
            "connectionmodule" => ModuleType.ConnectionModule,
            "defencemodule" => ModuleType.DefenceModule,
            "dockarea" => ModuleType.DockArea,
            "habitation" => ModuleType.Habitation,
            "pier" => ModuleType.Pier,
            "processingmodule" => ModuleType.ProcessingModule,
            "production" => ModuleType.Production,
            "storage" => ModuleType.Storage,
            _ => throw new ArgumentOutOfRangeException(nameof(value), value, "Unsupported module type."),
        };
    }

    public static string ToDataValue(this StorageKind storageKind) => storageKind switch
    {
        StorageKind.Condensate => "condensate",
        StorageKind.Container => "container",
        StorageKind.Liquid => "liquid",
        StorageKind.Solid => "solid",
        _ => throw new ArgumentOutOfRangeException(nameof(storageKind), storageKind, null),
    };

    public static StorageKind ToStorageKind(this string value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentOutOfRangeException(nameof(value), value, "Storage kind is required.");
        }

        return value.Trim().ToLowerInvariant() switch
        {
            "condensate" => StorageKind.Condensate,
            "container" => StorageKind.Container,
            "liquid" => StorageKind.Liquid,
            "solid" => StorageKind.Solid,
            _ => throw new ArgumentOutOfRangeException(nameof(value), value, "Unsupported storage kind."),
        };
    }

    public static StorageKind? ToNullableStorageKind(this string? value) =>
        string.IsNullOrWhiteSpace(value) ? null : value.ToStorageKind();

    public static string ToContractValue(this SpatialNodeKind kind) => kind switch
    {
        SpatialNodeKind.Star => "star",
        SpatialNodeKind.Planet => "planet",
        SpatialNodeKind.Moon => "moon",
        SpatialNodeKind.LagrangePoint => "lagrange-point",
        _ => throw new ArgumentOutOfRangeException(nameof(kind), kind, null),
    };

    public static string ToContractValue(this WorkStatus status) => status switch
    {
        WorkStatus.Pending => "pending",
        WorkStatus.Active => "active",
        WorkStatus.Blocked => "blocked",
        WorkStatus.Completed => "completed",
        WorkStatus.Failed => "failed",
        WorkStatus.Interrupted => "interrupted",
        _ => throw new ArgumentOutOfRangeException(nameof(status), status, null),
    };

    public static string ToContractValue(this OrderStatus status) => status switch
    {
        OrderStatus.Queued => "queued",
        OrderStatus.Active => "active",
        OrderStatus.Completed => "completed",
        OrderStatus.Cancelled => "cancelled",
        OrderStatus.Failed => "failed",
        OrderStatus.Interrupted => "interrupted",
        _ => throw new ArgumentOutOfRangeException(nameof(status), status, null),
    };

    public static string ToContractValue(this AiPlanStatus status) => status switch
    {
        AiPlanStatus.Planned => "planned",
        AiPlanStatus.Running => "running",
        AiPlanStatus.Blocked => "blocked",
        AiPlanStatus.Completed => "completed",
        AiPlanStatus.Failed => "failed",
        AiPlanStatus.Interrupted => "interrupted",
        _ => throw new ArgumentOutOfRangeException(nameof(status), status, null),
    };

    public static string ToContractValue(this AiPlanStepStatus status) => status switch
    {
        AiPlanStepStatus.Planned => "planned",
        AiPlanStepStatus.Running => "running",
        AiPlanStepStatus.Blocked => "blocked",
        AiPlanStepStatus.Completed => "completed",
        AiPlanStepStatus.Failed => "failed",
        AiPlanStepStatus.Interrupted => "interrupted",
        _ => throw new ArgumentOutOfRangeException(nameof(status), status, null),
    };

    public static string ToContractValue(this AiPlanSourceKind kind) => kind switch
    {
        AiPlanSourceKind.Rule => "rule",
        AiPlanSourceKind.Order => "order",
        AiPlanSourceKind.DefaultBehavior => "default-behavior",
        _ => throw new ArgumentOutOfRangeException(nameof(kind), kind, null),
    };

    public static string ToContractValue(this ShipOrderSourceKind kind) => kind switch
    {
        ShipOrderSourceKind.Player => "player",
        ShipOrderSourceKind.Behavior => "behavior",
        ShipOrderSourceKind.Commander => "commander",
        _ => throw new ArgumentOutOfRangeException(nameof(kind), kind, null),
    };

    public static string ToContractValue(this ShipState state) => state switch
    {
        ShipState.Idle => "idle",
        ShipState.Arriving => "arriving",
        ShipState.LocalFlight => "local-flight",
        ShipState.SpoolingWarp => "spooling-warp",
        ShipState.Warping => "warping",
        ShipState.SpoolingFtl => "spooling-ftl",
        ShipState.Ftl => "ftl",
        ShipState.CargoFull => "cargo-full",
        ShipState.MiningApproach => "mining-approach",
        ShipState.Mining => "mining",
        ShipState.NodeDepleted => "node-depleted",
        ShipState.AwaitingDock => "awaiting-dock",
        ShipState.DockingApproach => "docking-approach",
        ShipState.Docking => "docking",
        ShipState.Docked => "docked",
        ShipState.Transferring => "transferring",
        ShipState.Loading => "loading",
        ShipState.Unloading => "unloading",
        ShipState.WaitingMaterials => "waiting-materials",
        ShipState.ConstructionBlocked => "construction-blocked",
        ShipState.Constructing => "constructing",
        ShipState.DeliveringConstruction => "delivering-construction",
        ShipState.Blocked => "blocked",
        ShipState.Undocking => "undocking",
        ShipState.EngagingTarget => "engaging-target",
        ShipState.HoldingPosition => "holding-position",
        ShipState.Fleeing => "fleeing",
        _ => throw new ArgumentOutOfRangeException(nameof(state), state, null),
    };

    public static string ToContractValue(this SpaceLayerKind kind) => kind switch
    {
        SpaceLayerKind.UniverseSpace => "universe-space",
        SpaceLayerKind.GalaxySpace => "galaxy-space",
        SpaceLayerKind.SystemSpace => "system-space",
        SpaceLayerKind.LocalSpace => "local-space",
        _ => throw new ArgumentOutOfRangeException(nameof(kind), kind, null),
    };

    public static string ToContractValue(this MovementRegimeKind kind) => kind switch
    {
        MovementRegimeKind.LocalFlight => "local-flight",
        MovementRegimeKind.Warp => "warp",
        MovementRegimeKind.StargateTransit => "stargate-transit",
        MovementRegimeKind.FtlTransit => "ftl-transit",
        _ => throw new ArgumentOutOfRangeException(nameof(kind), kind, null),
    };
}
