using System.Text.Json;
using System.Text.Json.Serialization;

namespace MiGu.Server.Wms;

public sealed class TransportSelector
{
    public int SchemaVersion { get; set; } = 1;
    public StorageSelectorFilter? Storage { get; set; }
    public ContainerSelectorFilter? Container { get; set; }
    public MaterialSelectorFilter? Material { get; set; }
    public List<RankingRule> Ranking { get; set; } = [];
}

public sealed class StorageSelectorFilter
{
    public List<string> AreaIds { get; set; } = [];
    public List<string> StorageTypes { get; set; } = [];
    public List<string> ZoneCodes { get; set; } = [];
    public List<string> StatusIn { get; set; } = [];
    public List<string> SiteIds { get; set; } = [];
    public bool? AllowInbound { get; set; }
    public bool? AllowOutbound { get; set; }
    public bool RequireSiteId { get; set; }
    public bool RequireEmpty { get; set; }
    public bool RequireOccupied { get; set; }
    public List<string> ExcludeStorageIds { get; set; } = [];
}

public sealed class ContainerSelectorFilter
{
    public List<string> ContainerTypes { get; set; } = [];
    public List<string> StatusIn { get; set; } = [];
    public bool ExcludeReserved { get; set; } = true;
}

public sealed class MaterialSelectorFilter
{
    public List<string> MaterialIds { get; set; } = [];
    public List<string> Categories { get; set; } = [];
    public List<string> StatusIn { get; set; } = [];
    public decimal? MinQuantity { get; set; }
    public string BatchNoMode { get; set; } = "Any";
}

public sealed class RankingRule
{
    public string Field { get; set; } = "";
    public string Direction { get; set; } = "asc";
}

public sealed class TransportTaskOptions
{
    public bool AutoReserve { get; set; } = true;
    public bool RequireManualConfirm { get; set; }
    public bool AllowSameStorage { get; set; }
    public int ReservationTtlSeconds { get; set; } = 600;
    public string DispatchMode { get; set; } = "Manual";
    public int MaxCandidateCount { get; set; } = 20;
}

public static class TransportSelectorParser
{
    private static readonly JsonSerializerOptions Json = new(JsonSerializerDefaults.Web)
    {
        PropertyNameCaseInsensitive = true,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
    };

    public static TransportSelector ParseSelector(string? json)
    {
        if (string.IsNullOrWhiteSpace(json) || json.Trim() == "{}")
            return new TransportSelector();
        try
        {
            return JsonSerializer.Deserialize<TransportSelector>(json, Json) ?? new TransportSelector();
        }
        catch (JsonException ex)
        {
            throw new InvalidOperationException($"Selector JSON 无效: {ex.Message}");
        }
    }

    public static TransportTaskOptions ParseTaskOptions(string? json)
    {
        if (string.IsNullOrWhiteSpace(json) || json.Trim() == "{}")
            return new TransportTaskOptions();
        try
        {
            return JsonSerializer.Deserialize<TransportTaskOptions>(json, Json) ?? new TransportTaskOptions();
        }
        catch (JsonException ex)
        {
            throw new InvalidOperationException($"TaskOptions JSON 无效: {ex.Message}");
        }
    }

    public static string NormalizeSelectorJson(string? json) =>
        JsonSerializer.Serialize(ParseSelector(json), Json);

    public static string NormalizeTaskOptionsJson(string? json) =>
        JsonSerializer.Serialize(ParseTaskOptions(json), Json);
}

public sealed record WmsTransportRequest(
    string TriggerType,
    Guid? RuleId,
    string? RequestSiteId,
    Guid? MaterialId,
    decimal? Quantity,
    Guid? ContainerId,
    Guid? SourceStorageId,
    Guid? TargetStorageId,
    string? BatchNo,
    int Priority,
    string Reason,
    Dictionary<string, string>? Tags);

public sealed record TransportCandidatePair(
    Guid RuleId,
    string RuleCode,
    Guid SourceStorageId,
    string SourceStorageCode,
    Guid TargetStorageId,
    string TargetStorageCode,
    Guid ContainerId,
    string ContainerCode,
    Guid? MaterialId,
    string? MaterialCode,
    decimal? Quantity,
    int Score,
    List<string> RejectReasons);

public sealed record TransportCandidatePreview(
    WmsTransportRequest Request,
    List<TransportCandidatePair> Candidates,
    List<RulePreviewResult> RuleResults);

public sealed record RulePreviewResult(
    Guid RuleId,
    string RuleCode,
    string RuleName,
    int CandidateCount,
    List<string> RejectReasons);

public sealed record DispatchTransportCommand(
    Guid TaskId,
    string SourceSiteId,
    string TargetSiteId,
    string ContainerCode,
    int Priority,
    string BusinessType,
    string Reason);
