using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using ERPCore.Domain.Enums;

namespace ERPCore.Dtos.Production;

// Production run contract (docs/30-BACKEND-PHASE2.md §D.2–D.3).
//
// Statuses are never client-settable (02-SECURITY §B.6): a run's status and every stage
// status move only through the stage-action endpoints. Requests here carry quantities and
// references, nothing else.

// --- responses ---------------------------------------------------------------

/// <summary>Per-status stage counts driving the board's progress strip (FR-MFG-18, docs/21 §3).</summary>
public sealed record StageSummaryDto(int Waiting, int Ready, int InProgress, int Done, int Approved);

/// <summary>Row on the run board (docs/30 §D.2 <c>GET /production-runs</c>).</summary>
public sealed record RunSummaryDto(
    int RunId, string DocNo, int TemplateId, string TemplateName,
    decimal TargetQty, ProductionRunStatus Status, int ReworkCount,
    StageSummaryDto StageSummary, int WarehouseId,
    int? FinishedItemId, string? FinishedItemName,
    int CreatedBy, DateTime CreatedAt, DateTime? CompletedAt);

/// <summary>
/// The run cost pool (FR-MFG-13). Always derived from the stage inputs, never stored —
/// surfaced so the UI can preview the finished unit cost before approving the terminal.
/// </summary>
public sealed record CostPoolDto(decimal Consumed, decimal Returned, decimal Net);

/// <summary>
/// One input of a run stage. <c>PlannedQty</c> is expressed in <c>QtyUnit</c> — content
/// (ml/g) or packs — while every consumption figure is always a pack count, so the two are
/// not directly comparable for a Content input.
/// </summary>
public sealed record RunStageInputDto(
    int RunInputId, StageInputSource Source, int? ItemId, int? FromRunOutputId, StageQtyUnit QtyUnit,
    decimal PlannedQty, decimal ConsumedQty, decimal ConsumedValue,
    decimal DeliveredQty, decimal ReturnedQty, decimal ReturnedValue);

/// <summary>
/// One output of a run stage. <c>AvailableToTransfer</c> is derived — produced − scrapped −
/// transferred (FR-MFG-12) — and never stored. <c>UomId</c> is the WIP label and is null on
/// the terminal output, whose unit is the finished item's base UOM.
/// </summary>
public sealed record RunStageOutputDto(
    int RunOutputId, int? ItemId, string Name, int? UomId,
    decimal PlannedQty, decimal ProducedQty, decimal ScrappedQty, int? ScrapReasonCodeId,
    decimal TransferredQty, decimal AvailableToTransfer);

/// <summary>
/// One stage of a run. <c>IsTerminal</c> (no outbound edge) and <c>IsEntry</c> (no inbound
/// edge) are derived from the run edge set rather than stored, so they cannot drift from it.
/// <c>ActualMinutes</c> is the elapsed whole minutes once the stage has finished, null while
/// it is still running (FR-MFG-19). <c>FieldValues</c> is the raw jsonb captured at complete,
/// passed through verbatim.
/// </summary>
public sealed record RunStageDto(
    int RunStageId, int? TemplateStageId, string Name, string? RoleLabel,
    int EstimatedMinutes, decimal PosX, decimal PosY,
    ProductionStageStatus Status, bool IsTerminal, bool IsEntry,
    DateTime? ActualStartAt, DateTime? ActualEndAt, int? ActualMinutes,
    IReadOnlyList<FieldDefDto> FieldDefs, JsonElement? FieldValues,
    IReadOnlyList<RunStageInputDto> Inputs, IReadOnlyList<RunStageOutputDto> Outputs);

public sealed record RunEdgeDto(int RunEdgeId, int ParentRunStageId, int ChildRunStageId);

public sealed record RunEventDto(
    int EventId, int? RunStageId, RunStageEventType EventType, string? Note,
    JsonElement? Payload, int UserId, DateTime CreatedAt);

/// <summary>Full run graph (docs/30 §D.2 <c>GET /production-runs/{id}</c>).</summary>
public sealed record RunGraphDto(
    int RunId, string DocNo, int TemplateId, string TemplateName,
    int WarehouseId, int? OutputBinId,
    decimal TargetQty, decimal ScaleFactor,
    ProductionRunStatus Status, int ReworkCount, int? CancelReasonCodeId,
    CostPoolDto CostPool,
    IReadOnlyList<RunStageDto> Stages, IReadOnlyList<RunEdgeDto> Edges, IReadOnlyList<RunEventDto> Events,
    int CreatedBy, DateTime CreatedAt, DateTime? CompletedAt);

// --- requests ----------------------------------------------------------------

public sealed class CreateRunRequest
{
    [Range(1, int.MaxValue)]
    public int TemplateId { get; set; }

    /// <summary>Quantity of the finished item; drives the whole graph's scale factor (FR-MFG-08).</summary>
    [Range(0.0001, double.MaxValue)]
    public decimal TargetQty { get; set; }

    [Range(1, int.MaxValue)]
    public int WarehouseId { get; set; }

    /// <summary>Optional bin for the finished goods; must belong to <see cref="WarehouseId"/>.</summary>
    public int? OutputBinId { get; set; }
}

/// <summary>
/// Per-run scaling override (FR-MFG-08). Only accepted while the stage has not started
/// (<c>409 STAGE_NOT_EDITABLE</c>).
/// </summary>
public sealed class UpdateStageQuantitiesRequest
{
    public List<StageQuantityLine> Inputs { get; set; } = new();
    public List<StageQuantityLine> Outputs { get; set; } = new();
}

public sealed class StageQuantityLine
{
    /// <summary>The <c>runInputId</c> or <c>runOutputId</c> being adjusted.</summary>
    [Range(1, int.MaxValue)]
    public int Id { get; set; }

    [Range(0.0001, double.MaxValue)]
    public decimal PlannedQty { get; set; }
}
