using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using ROLAC.API.Authorization;
using ROLAC.API.DTOs.Giving;
using ROLAC.API.Services;

namespace ROLAC.API.Controllers;

[ApiController]
[Route("api/offering-sessions")]
[Authorize]
public class OfferingSessionsController : ControllerBase
{
    private readonly IOfferingSessionService _svc;
    public OfferingSessionsController(IOfferingSessionService svc) => _svc = svc;

    [HttpGet]
    [HasPermission(Modules.OfferingSessions, PermissionActions.Read)]
    public async Task<IActionResult> GetPaged(
        [FromQuery] int page = 1, [FromQuery] int pageSize = 20,
        [FromQuery] DateOnly? from = null, [FromQuery] DateOnly? to = null)
        => Ok(await _svc.GetPagedAsync(page, pageSize, from, to));

    [HttpGet("check-date")]
    [HasPermission(Modules.OfferingSessions, PermissionActions.Read)]
    public async Task<IActionResult> CheckDate([FromQuery] DateOnly date)
        => Ok(new { exists = await _svc.DateExistsAsync(date) });

    [HttpGet("{id:int}")]
    [HasPermission(Modules.OfferingSessions, PermissionActions.Read)]
    public async Task<IActionResult> GetById(int id)
    {
        var dto = await _svc.GetByIdAsync(id);
        return dto is null ? NotFound() : Ok(dto);
    }

    [HttpPost]
    [HasPermission(Modules.OfferingSessions, PermissionActions.Write)]
    public async Task<IActionResult> Create([FromBody] CreateOfferingSessionRequest request)
    {
        try
        {
            var id = await _svc.CreateAsync(request);
            return CreatedAtAction(nameof(GetById), new { id }, new { id });
        }
        catch (InvalidOperationException ex) { return Conflict(new { message = ex.Message }); }
    }

    [HttpPost("{id:int}/reopen")]
    [HasPermission(Modules.OfferingSessions, PermissionActions.Approve)]
    public async Task<IActionResult> Reopen(int id)
    {
        try   { await _svc.ReopenAsync(id); return NoContent(); }
        catch (KeyNotFoundException)         { return NotFound(); }
        catch (InvalidOperationException ex) { return Conflict(new { message = ex.Message }); }
    }

    [HttpPut("{id:int}")]
    [HasPermission(Modules.OfferingSessions, PermissionActions.Write)]
    public async Task<IActionResult> Replace(int id, [FromBody] CreateOfferingSessionRequest request)
    {
        try   { await _svc.ReplaceAsync(id, request); return NoContent(); }
        catch (KeyNotFoundException)         { return NotFound(); }
        catch (InvalidOperationException ex) { return Conflict(new { message = ex.Message }); }
    }

    // ── Paper-proof PDF (merged client-side, one file per session) ───────────

    [HttpPost("{id:int}/proof")]
    [HasPermission(Modules.OfferingSessions, PermissionActions.Write)]
    [RequestSizeLimit(52_428_800)]   // 50 MB — a merged multi-image PDF is larger than one receipt
    public async Task<IActionResult> UploadProof(int id, IFormFile file)
    {
        if (file is null || file.Length == 0) return BadRequest(new { message = "No file." });
        if (file.ContentType != "application/pdf") return BadRequest(new { message = "Proof must be a PDF." });
        try
        {
            await using var stream = file.OpenReadStream();
            await _svc.SaveProofAsync(id, stream, file.FileName);
            return NoContent();
        }
        catch (KeyNotFoundException) { return NotFound(); }
    }

    [HttpGet("{id:int}/proof")]
    [HasPermission(Modules.OfferingSessions, PermissionActions.Read)]
    public async Task<IActionResult> GetProof(int id)
    {
        try
        {
            var result = await _svc.OpenProofAsync(id);
            if (result is null) return NotFound();
            return File(result.Value.stream, result.Value.contentType);
        }
        catch (KeyNotFoundException) { return NotFound(); }
    }

    [HttpDelete("{id:int}/proof")]
    [HasPermission(Modules.OfferingSessions, PermissionActions.Delete)]
    public async Task<IActionResult> DeleteProof(int id)
    {
        try   { await _svc.DeleteProofAsync(id); return NoContent(); }
        catch (KeyNotFoundException) { return NotFound(); }
    }
}
