using ERPCore.Domain.Enums;
using ERPCore.Dtos.Common;
using ERPCore.Dtos.Hrm;
using ERPCore.Infra.Auth;
using ERPCore.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;

namespace ERPCore.Controllers.Hrm;

/// <summary>Payroll run endpoints (docs/13-BACKEND-HRM-API.md §6).</summary>
[Route("api/v1/payroll-runs")]
public sealed class PayrollRunsController : ApiControllerBase
{
    private readonly IPayrollRunService _payrollRuns;
    private readonly ICurrentUser _currentUser;

    public PayrollRunsController(IPayrollRunService payrollRuns, ICurrentUser currentUser)
    {
        _payrollRuns = payrollRuns;
        _currentUser = currentUser;
    }

    [HttpGet]
    [ProducesResponseType(typeof(PagedResponse<PayrollRunDto>), StatusCodes.Status200OK)]
    public async Task<ActionResult<PagedResponse<PayrollRunDto>>> List(
        [FromQuery] PageQuery query, [FromQuery] int? periodYear, [FromQuery] int? periodMonth,
        [FromQuery] PayrollRunStatus? status, CancellationToken ct)
        => Ok(await _payrollRuns.ListAsync(query, periodYear, periodMonth, status, ct));

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

    [HttpGet("{payrollRunId:int}/lines")]
    [ProducesResponseType(typeof(List<PayrollLineDto>), StatusCodes.Status200OK)]
    public async Task<ActionResult<List<PayrollLineDto>>> ListLines(int payrollRunId, CancellationToken ct)
        => Ok(await _payrollRuns.ListLinesAsync(payrollRunId, ct));

    [HttpGet("{payrollRunId:int}/lines/{lineId:int}")]
    [ProducesResponseType(typeof(PayrollLineDetailDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<ActionResult<PayrollLineDetailDto>> GetLine(int payrollRunId, int lineId, CancellationToken ct)
    {
        var result = await _payrollRuns.GetLineAsync(payrollRunId, lineId, ct);
        return result is null ? NotFound() : Ok(result);
    }

    [HttpPost]
    [ProducesResponseType(typeof(PayrollRunDto), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
    public async Task<ActionResult<PayrollRunDto>> Generate([FromBody] GeneratePayrollRunRequest request, CancellationToken ct)
    {
        var result = await _payrollRuns.GenerateAsync(request, _currentUser.AuditUserId, ct);
        return Created($"/api/v1/payroll-runs/{result.PayrollRunId}", result);
    }

    [HttpPost("{payrollRunId:int}/approve")]
    [ProducesResponseType(typeof(PayrollRunDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<ActionResult<PayrollRunDto>> Approve(int payrollRunId, CancellationToken ct)
        => Ok(await _payrollRuns.ApproveAsync(payrollRunId, _currentUser.AuditUserId, ct));

    [HttpPost("{payrollRunId:int}/lock")]
    [ProducesResponseType(typeof(PayrollRunDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<ActionResult<PayrollRunDto>> Lock(int payrollRunId, CancellationToken ct)
        => Ok(await _payrollRuns.LockAsync(payrollRunId, _currentUser.AuditUserId, ct));

    [HttpPost("{payrollRunId:int}/unlock")]
    [ProducesResponseType(typeof(PayrollRunDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<ActionResult<PayrollRunDto>> Unlock(int payrollRunId, [FromBody] UnlockPayrollRunRequest request, CancellationToken ct)
        => Ok(await _payrollRuns.UnlockAsync(payrollRunId, request.Reason, _currentUser.AuditUserId, ct));

    [HttpPost("{payrollRunId:int}/generate-payslips")]
    [ProducesResponseType(typeof(List<PayslipDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<ActionResult<List<PayslipDto>>> GeneratePayslips(int payrollRunId, CancellationToken ct)
        => Ok(await _payrollRuns.GeneratePayslipsAsync(payrollRunId, ct));
}
