using ERPCore.Domain.Enums;
using ERPCore.Dtos.Common;
using ERPCore.Dtos.Production;
using ERPCore.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;

namespace ERPCore.Controllers;

/// <summary>Production run endpoints (docs/30-BACKEND-PHASE2.md §D.2–D.3).</summary>
[Route("api/v1/production-runs")]
public sealed class ProductionRunsController : ApiControllerBase
{
    private readonly IProductionRunService _runs;

    public ProductionRunsController(IProductionRunService runs) => _runs = runs;

    [HttpGet]
    [ProducesResponseType(typeof(PagedResponse<RunSummaryDto>), StatusCodes.Status200OK)]
    public async Task<ActionResult<PagedResponse<RunSummaryDto>>> List(
        [FromQuery] PageQuery query,
        [FromQuery] ProductionRunStatus? status,
        [FromQuery] int? templateId,
        [FromQuery] int? warehouseId,
        CancellationToken ct)
        => Ok(await _runs.ListAsync(query, status, templateId, warehouseId, ct));

    [HttpGet("{runId:int}")]
    [ProducesResponseType(typeof(RunGraphDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<RunGraphDto>> GetById(int runId, CancellationToken ct)
    {
        var result = await _runs.GetAsync(runId, ct);
        if (result is null) return NotFound();

        SetETag(result.RowVersion);
        return Ok(result.Value);
    }

    [HttpPost]
    [ProducesResponseType(typeof(RunGraphDto), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
    public async Task<ActionResult<RunGraphDto>> Create([FromBody] CreateRunRequest request, CancellationToken ct)
    {
        var result = await _runs.CreateAsync(request, ct);

        SetETag(result.RowVersion);
        return Created($"/api/v1/production-runs/{result.Value.RunId}", result.Value);
    }

    [HttpPut("{runId:int}/stages/{runStageId:int}/quantities")]
    [ProducesResponseType(typeof(RunStageDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
    public async Task<ActionResult<RunStageDto>> UpdateQuantities(
        int runId, int runStageId, [FromBody] UpdateStageQuantitiesRequest request, CancellationToken ct)
        => Ok(await _runs.UpdateStageQuantitiesAsync(runId, runStageId, request, ct));

    // --- stage actions (docs/30 §D.3) ---------------------------------------
    //
    // Idempotency-Key is accepted on every action to match the Phase-1 contract (docs/11
    // §1.6) but, as in GrnService.ConfirmAsync, it is not stored. Replay safety comes from
    // the status guards instead: a double-fire finds the stage already moved on and gets a
    // 409, which docs/21 §6 tells the client to treat as a silent refetch. Recorded as a
    // deviation from §D.3's "idempotency-key honored".

    [HttpPost("{runId:int}/stages/{runStageId:int}/start")]
    [ProducesResponseType(typeof(StartStageResultDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
    public async Task<ActionResult<StartStageResultDto>> Start(
        int runId, int runStageId,
        [FromHeader(Name = "Idempotency-Key")] string? idempotencyKey,
        CancellationToken ct)
        => Ok(await _runs.StartStageAsync(runId, runStageId, ct));

    [HttpPost("{runId:int}/stages/{runStageId:int}/complete")]
    [ProducesResponseType(typeof(RunStageDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
    public async Task<ActionResult<RunStageDto>> Complete(
        int runId, int runStageId, [FromBody] CompleteStageRequest request,
        [FromHeader(Name = "Idempotency-Key")] string? idempotencyKey,
        CancellationToken ct)
        => Ok(await _runs.CompleteStageAsync(runId, runStageId, request, ct));

    [HttpPost("{runId:int}/stages/{runStageId:int}/approve")]
    [ProducesResponseType(typeof(ApproveStageResultDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
    public async Task<ActionResult<ApproveStageResultDto>> Approve(
        int runId, int runStageId, [FromBody] ApproveStageRequest? request,
        [FromHeader(Name = "Idempotency-Key")] string? idempotencyKey,
        CancellationToken ct)
        => Ok(await _runs.ApproveStageAsync(runId, runStageId, request ?? new ApproveStageRequest(), ct));

    [HttpPost("{runId:int}/stages/{runStageId:int}/transfer")]
    [ProducesResponseType(typeof(TransferResultDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
    public async Task<ActionResult<TransferResultDto>> Transfer(
        int runId, int runStageId, [FromBody] TransferRemainderRequest request,
        [FromHeader(Name = "Idempotency-Key")] string? idempotencyKey,
        CancellationToken ct)
        => Ok(await _runs.TransferAsync(runId, runStageId, request, ct));

    [HttpPost("{runId:int}/inputs/{runInputId:int}/return-leftover")]
    [ProducesResponseType(typeof(ReturnLeftoverResultDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
    public async Task<ActionResult<ReturnLeftoverResultDto>> ReturnLeftover(
        int runId, int runInputId, [FromBody] ReturnLeftoverRequest request,
        [FromHeader(Name = "Idempotency-Key")] string? idempotencyKey,
        CancellationToken ct)
        => Ok(await _runs.ReturnLeftoverAsync(runId, runInputId, request, ct));

    [HttpPost("{runId:int}/stages/{runStageId:int}/reject-intake")]
    [ProducesResponseType(typeof(RejectIntakeResultDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<ActionResult<RejectIntakeResultDto>> RejectIntake(
        int runId, int runStageId, [FromBody] RejectRequest? request,
        [FromHeader(Name = "Idempotency-Key")] string? idempotencyKey,
        CancellationToken ct)
        => Ok(await _runs.RejectIntakeAsync(runId, runStageId, request ?? new RejectRequest(), ct));

    /// <summary>Terminal reject — resets the whole run for a rework pass (FR-MFG-16).</summary>
    [HttpPost("{runId:int}/stages/{runStageId:int}/reject")]
    [ProducesResponseType(typeof(TerminalRejectResultDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<ActionResult<TerminalRejectResultDto>> Reject(
        int runId, int runStageId, [FromBody] RejectRequest? request,
        [FromHeader(Name = "Idempotency-Key")] string? idempotencyKey,
        CancellationToken ct)
        => Ok(await _runs.RejectTerminalAsync(runId, runStageId, request ?? new RejectRequest(), ct));

    [HttpPost("{runId:int}/cancel")]
    [ProducesResponseType(typeof(CancelRunResultDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
    public async Task<ActionResult<CancelRunResultDto>> Cancel(
        int runId, [FromBody] CancelRunRequest request,
        [FromHeader(Name = "Idempotency-Key")] string? idempotencyKey,
        CancellationToken ct)
        => Ok(await _runs.CancelAsync(runId, request, ct));
}
