using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/v1/cover-sheets")]
[Produces("application/json")]
[Authorize]
public class CoverSheetController : ControllerBase
{
    private readonly ICoverSheetService _coverSheets;

    public CoverSheetController(ICoverSheetService coverSheets)
    {
        _coverSheets = coverSheets;
    }

    /// <summary>
    /// Generates one or more cover sheets with unique barcode codes.
    /// Each cover sheet encodes batch type, track, optional patient, and
    /// optional entry clerk assignment.
    /// </summary>
    [HttpPost("generate")]
    [Authorize(Roles = "INTAKE_CLERK,ADMINISTRATOR")]
    [ProducesResponseType(typeof(ApiResponse<List<CoverSheetResponse>>), StatusCodes.Status201Created)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    public async Task<IActionResult> Generate([FromBody] GenerateCoverSheetsRequest request)
    {
        var actorUserId = Guid.Parse(User.FindFirstValue(ClaimTypes.NameIdentifier)!);
        var sheets = await _coverSheets.GenerateAsync(request, actorUserId);
        var response = sheets.Select(MapToResponse).ToList();
        return StatusCode(201, ApiResponse<List<CoverSheetResponse>>.Created(response));
    }

    /// <summary>
    /// Looks up a cover sheet by its barcode code. Used during barcode-assisted
    /// upload to auto-populate batch type, track, patient, and clerk assignment.
    /// </summary>
    [HttpGet("lookup/{code}")]
    [ProducesResponseType(typeof(ApiResponse<CoverSheetResponse>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    public async Task<IActionResult> Lookup(string code)
    {
        var sheet = await _coverSheets.LookupByCodeAsync(code);
        if (sheet is null)
            return NotFound(ApiResponse<object>.Fail(404, "Cover sheet not found.", "COVER_SHEET_NOT_FOUND"));

        return Ok(ApiResponse<CoverSheetResponse>.Ok(MapToResponse(sheet)));
    }

    /// <summary>
    /// Lists cover sheets with optional filters.
    /// </summary>
    [HttpGet]
    [Authorize(Roles = "INTAKE_CLERK,ADMINISTRATOR")]
    [ProducesResponseType(typeof(ApiResponse<List<CoverSheetResponse>>), StatusCodes.Status200OK)]
    public async Task<IActionResult> List(
        [FromQuery] bool? isUsed,
        [FromQuery] Guid? patientId,
        [FromQuery] int page = 1,
        [FromQuery] int pageSize = 20)
    {
        var sheets = await _coverSheets.ListAsync(isUsed, patientId, page, pageSize);
        var response = sheets.Select(MapToResponse).ToList();
        return Ok(ApiResponse<List<CoverSheetResponse>>.Ok(response));
    }

    /// <summary>
    /// Generates a printable PDF containing cover sheets with QR codes.
    /// Each page has the cover sheet code as a QR code, plus human-readable
    /// batch type, patient info, and generation date.
    /// </summary>
    [HttpPost("{id:guid}/pdf")]
    [Authorize(Roles = "INTAKE_CLERK,ADMINISTRATOR")]
    [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GeneratePdf(Guid id)
    {
        var sheet = await _coverSheets.LookupByIdAsync(id);
        if (sheet is null)
            return NotFound(ApiResponse<object>.Fail(404, "Cover sheet not found.", "COVER_SHEET_NOT_FOUND"));

        var pdfBytes = CoverSheetPdfGenerator.Generate(sheet);
        return File(pdfBytes, "application/pdf", $"coversheet-{sheet.Code}.pdf");
    }

    /// <summary>
    /// Generates a batch PDF containing multiple cover sheets (one per page).
    /// Accepts a list of cover sheet IDs.
    /// </summary>
    [HttpPost("batch-pdf")]
    [Authorize(Roles = "INTAKE_CLERK,ADMINISTRATOR")]
    [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
    public async Task<IActionResult> GenerateBatchPdf([FromBody] BatchPdfRequest request)
    {
        var sheets = await _coverSheets.GetByIdsAsync(request.CoverSheetIds);
        var pdfBytes = CoverSheetPdfGenerator.GenerateBatch(sheets);
        return File(pdfBytes, "application/pdf", $"coversheets-batch-{DateTime.UtcNow:yyyyMMdd}.pdf");
    }

    private static CoverSheetResponse MapToResponse(CoverSheet sheet) => new(
        Id: sheet.Id,
        Code: sheet.Code,
        BatchType: sheet.BatchType.ToDbString(),
        Track: sheet.Track.ToDbString(),
        PatientId: sheet.PatientId,
        PatientName: sheet.Patient?.FullName,
        PatientMrn: sheet.Patient?.Mrn,
        AssignToUserId: sheet.AssignToUserId,
        AssignToUserName: sheet.AssignToUser?.FullName,
        IsUsed: sheet.IsUsed,
        BatchId: sheet.BatchId,
        CreatedAt: sheet.CreatedAt,
        UsedAt: sheet.UsedAt
    );
}