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>Attendance upload batch endpoints (docs/13-BACKEND-HRM-API.md §4).</summary>
[Route("api/v1/attendance-batches")]
public sealed class AttendanceBatchesController : ApiControllerBase
{
    private readonly IAttendanceUploadService _attendance;
    private readonly ICurrentUser _currentUser;

    public AttendanceBatchesController(IAttendanceUploadService attendance, ICurrentUser currentUser)
    {
        _attendance = attendance;
        _currentUser = currentUser;
    }

    [HttpGet("template.xlsx")]
    [ProducesResponseType(StatusCodes.Status200OK)]
    public IActionResult DownloadTemplate([FromQuery] string? format)
    {
        var (content, contentType, fileName) = _attendance.GenerateTemplate(string.Equals(format, "csv", StringComparison.OrdinalIgnoreCase));
        return File(content, contentType, fileName);
    }

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

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

    [HttpPost]
    [RequestSizeLimit(20 * 1024 * 1024)]
    [ProducesResponseType(typeof(AttendanceUploadBatchDto), StatusCodes.Status201Created)]
    [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
    public async Task<ActionResult<AttendanceUploadBatchDto>> Upload(
        [FromForm] UploadAttendanceBatchMetadata metadata, IFormFile file, CancellationToken ct)
    {
        await using var stream = file.OpenReadStream();
        var result = await _attendance.UploadAsync(stream, file.FileName, metadata.PeriodStart, metadata.PeriodEnd, _currentUser.AuditUserId, ct);
        return Created($"/api/v1/attendance-batches/{result.AttendanceUploadBatchId}", result);
    }

    [HttpGet("{batchId:int}/records")]
    [ProducesResponseType(typeof(List<AttendanceRecordDto>), StatusCodes.Status200OK)]
    public async Task<ActionResult<List<AttendanceRecordDto>>> ListRecords(
        int batchId, [FromQuery] RowValidationStatus? status, CancellationToken ct)
        => Ok(await _attendance.ListRecordsAsync(batchId, status, ct));

    [HttpPut("{batchId:int}/records/{recordId:int}")]
    [ProducesResponseType(typeof(AttendanceRecordDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<ActionResult<AttendanceRecordDto>> UpdateRecord(
        int batchId, int recordId, [FromBody] UpdateAttendanceRecordRequest request, CancellationToken ct)
        => Ok(await _attendance.UpdateRecordAsync(batchId, recordId, request, _currentUser.AuditUserId, ct));

    [HttpPost("{batchId:int}/resolve-duplicate")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<IActionResult> ResolveDuplicate(int batchId, [FromBody] ResolveDuplicateRequest request, CancellationToken ct)
    {
        await _attendance.ResolveDuplicateAsync(batchId, request, ct);
        return NoContent();
    }

    [HttpPost("{batchId:int}/validate")]
    [ProducesResponseType(typeof(AttendanceUploadBatchDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
    public async Task<ActionResult<AttendanceUploadBatchDto>> Validate(int batchId, CancellationToken ct)
        => Ok(await _attendance.ValidateAsync(batchId, ct));

    [HttpPost("{batchId:int}/confirm")]
    [ProducesResponseType(typeof(AttendanceUploadBatchDto), StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status409Conflict)]
    public async Task<ActionResult<AttendanceUploadBatchDto>> Confirm(int batchId, CancellationToken ct)
        => Ok(await _attendance.ConfirmAsync(batchId, _currentUser.AuditUserId, ct));

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