using ERPCore.Common.Http;
using ERPCore.Domain.Enums;
using ERPCore.Dtos.Common;
using ERPCore.Dtos.Production;

namespace ERPCore.Services.Interfaces;

/// <summary>
/// Production run lifecycle (docs/30 §D.2–D.3, FR-MFG-08..19). Every stock-affecting
/// action runs inside a single <c>ExecuteInTransactionAsync</c> scope and consumes stock
/// only through <c>IFifoCostingService</c> (NFR-02/NFR-05).
/// </summary>
public interface IProductionRunService
{
    Task<PagedResponse<RunSummaryDto>> ListAsync(
        PageQuery query, ProductionRunStatus? status, int? templateId, int? warehouseId,
        CancellationToken ct = default);

    Task<ETagged<RunGraphDto>?> GetAsync(int runId, CancellationToken ct = default);

    /// <summary>
    /// Instantiates a template (FR-MFG-08): copies every stage, input, output and edge,
    /// scales all quantities by <c>targetQty / terminalOutputQtyPerBatch</c>, issues a
    /// <c>PRD-…</c> document number, and leaves entry stages Ready with the rest Waiting.
    /// </summary>
    Task<ETagged<RunGraphDto>> CreateAsync(CreateRunRequest request, CancellationToken ct = default);

    /// <summary>
    /// Per-run quantity override on a stage that has not started
    /// (<c>409 STAGE_NOT_EDITABLE</c> once it has). Re-evaluates the stage's readiness,
    /// since raising an upstream input's planned quantity can un-ready it.
    /// </summary>
    Task<RunStageDto> UpdateStageQuantitiesAsync(
        int runId, int runStageId, UpdateStageQuantitiesRequest request, CancellationToken ct = default);

    /// <summary>
    /// <c>Ready → InProgress</c> (FR-MFG-10). FIFO-consumes every Stock input from the run
    /// warehouse in one transaction and stamps <c>actualStartAt</c>.
    /// <para>Consumes <c>max(0, plannedBase − consumedQty)</c> per input, so a rework
    /// restart with an unchanged planned quantity consumes nothing and one with a raised
    /// planned quantity consumes only the delta (FR-MFG-16).</para>
    /// </summary>
    Task<StartStageResultDto> StartStageAsync(int runId, int runStageId, CancellationToken ct = default);

    /// <summary>
    /// <c>InProgress → Done</c> (FR-MFG-11). Records produced and scrapped quantities per
    /// output plus the custom field values. A re-complete after a rework <b>overwrites</b>
    /// the previous figures rather than adding to them.
    /// </summary>
    Task<RunStageDto> CompleteStageAsync(
        int runId, int runStageId, CompleteStageRequest request, CancellationToken ct = default);

    /// <summary>
    /// <c>Done → Approved</c> (FR-MFG-12/13). Non-terminal: hands WIP to the children,
    /// defaulting to the full available quantity. Terminal: posts the production receipt —
    /// a finished-goods layer costed at <c>costPool / goodQty</c> — and completes the run.
    /// </summary>
    Task<ApproveStageResultDto> ApproveStageAsync(
        int runId, int runStageId, ApproveStageRequest request, CancellationToken ct = default);

    /// <summary>
    /// Later partial transfer of a remainder held on an already-Approved stage (FR-MFG-12),
    /// never exceeding produced − scrapped − already transferred.
    /// </summary>
    Task<TransferResultDto> TransferAsync(
        int runId, int runStageId, TransferRemainderRequest request, CancellationToken ct = default);

    /// <summary>
    /// Returns unconsumed material to stock before the receipt closes the pool (FR-MFG-14).
    /// The inbound layer is created at the <b>weighted cost actually consumed</b> for that
    /// input, so the move is cost-preserving and the pool reduces by exactly what leaves it.
    /// <c>409 RUN_COST_CLOSED</c> once the run has completed.
    /// </summary>
    Task<ReturnLeftoverResultDto> ReturnLeftoverAsync(
        int runId, int runInputId, ReturnLeftoverRequest request, CancellationToken ct = default);

    /// <summary>
    /// Downstream reject (FR-MFG-15): this stage rejects the work it received, its delivering
    /// parents revert <c>Approved → InProgress</c> with their transferred quantities pulled
    /// back, and this stage returns to Waiting. Consumed stock stays consumed.
    /// </summary>
    Task<RejectIntakeResultDto> RejectIntakeAsync(
        int runId, int runStageId, RejectRequest request, CancellationToken ct = default);

    /// <summary>
    /// Terminal reject (FR-MFG-16): resets the whole run to its starting stages, increments
    /// <c>reworkCount</c> and snapshots the discarded figures into the event history.
    /// Already-consumed material remains in the cost pool.
    /// </summary>
    Task<TerminalRejectResultDto> RejectTerminalAsync(
        int runId, int runStageId, RejectRequest request, CancellationToken ct = default);

    /// <summary>
    /// Cancels an in-progress run (FR-MFG-17). Net consumed-and-not-returned stock goes back
    /// at its consumed weighted cost; scrapped output quantities are written off on the event.
    /// <c>409 RUN_NOT_CANCELLABLE</c> for a completed run.
    /// </summary>
    Task<CancelRunResultDto> CancelAsync(int runId, CancelRunRequest request, CancellationToken ct = default);
}
