using GestionaDenuncias.Shared.Models;
using ApiDenuncias.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace ApiDenuncias.Controllers;

[ApiController]
[Authorize]
[Route("api/gestiona")]
public sealed class GestionaController : ControllerBase
{
    private readonly IGestionaService _gestiona;
    private readonly GestionaDocumentWorkflowService _workflow;

    public GestionaController(
        IGestionaService gestiona,
        GestionaDocumentWorkflowService workflow)
    {
        _gestiona = gestiona;
        _workflow = workflow;
    }

    [HttpPost("files")]
    public async Task<ActionResult<GestionaCreateFileResponse>> CreateFile(
        GestionaCreateFileRequest request,
        CancellationToken cancellationToken)
    {
        try
        {
            var file = await _gestiona.CreateFileAsync(
                request.Subject,
                request.DocumentSeries,
                request.SiaCode);

            return Ok(file);
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new ApiError(ex.Message));
        }
    }

    [HttpPost("files/open")]
    public async Task<IActionResult> OpenFile(
        GestionaOpenFileRequest request,
        CancellationToken cancellationToken)
    {
        try
        {
            await _gestiona.OpenFileAsync(
                request.FileUrl,
                request.FileOpenUrl,
                request.AssignedGroupCode,
                request.Confidential,
                request.FreeTitle);

            return Ok(new { ok = true });
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new ApiError(ex.Message));
        }
    }

    [HttpPost("files/assignees")]
    public async Task<IActionResult> AssignFile(
        GestionaAssignFileRequest request,
        CancellationToken cancellationToken)
    {
        try
        {
            await _gestiona.AssignFileAsync(
                request.FileUrl,
                request.AssignedGroupCode);

            return Ok(new { ok = true });
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new ApiError(ex.Message));
        }
    }

    [HttpGet("files/by-url")]
    public async Task<ActionResult<GestionaExpedienteInfo?>> GetFileByUrl(
        [FromQuery] string fileUrl,
        CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(fileUrl))
        {
            return BadRequest(new ApiError("Debes indicar la URL del expediente de Gestiona."));
        }

        try
        {
            return Ok(await _gestiona.ObtenerExpedienteAsync(fileUrl));
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new ApiError(ex.Message));
        }
    }

    [HttpGet("files/audit/latest")]
    public async Task<ActionResult<GestionaAuditInfo?>> GetLatestFileAudit(
        [FromQuery] string fileUrl,
        CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(fileUrl))
        {
            return BadRequest(new ApiError("Debes indicar la URL del expediente de Gestiona."));
        }

        try
        {
            return Ok(await _gestiona.ObtenerUltimaAuditoriaExpedienteAsync(fileUrl));
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new ApiError(ex.Message));
        }
    }

    [HttpPost("thirds/ensure-link")]
    public async Task<IActionResult> EnsureThirdAndLink(
        GestionaEnsureThirdRequest request,
        CancellationToken cancellationToken)
    {
        if (request.ThirdParty is null)
        {
            return BadRequest(new ApiError("Faltan los datos del tercero."));
        }

        try
        {
            return Ok(await _gestiona.AsegurarTerceroYEnlazarAsync(request.FileUrl, request.ThirdParty));
        }
        catch (ArgumentException ex)
        {
            return BadRequest(new ApiError(ex.Message));
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new ApiError(ex.Message));
        }
    }

    [HttpPost("folders")]
    public async Task<ActionResult<GestionaCreateFolderResponse>> CreateFolder(
        GestionaCreateFolderRequest request,
        CancellationToken cancellationToken)
    {
        try
        {
            var folderId = await _gestiona.CreateFolderAsync(request.FileUrl, request.FolderName);
            var documentsTargetUrl = $"{request.FileUrl.TrimEnd('/')}/documents-and-folders/{folderId}";
            return Ok(new GestionaCreateFolderResponse(folderId, documentsTargetUrl));
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new ApiError(ex.Message));
        }
    }

    [HttpPost("documents")]
    public async Task<ActionResult<GestionaUploadDocumentResponse>> UploadDocument(
        GestionaUploadDocumentRequest request,
        CancellationToken cancellationToken)
    {
        try
        {
            var documentUrl = await _workflow.UploadDocumentAndReturnUrlAsync(
                request.FileUrl,
                request.ContentBytes,
                request.FileName);

            return Ok(new GestionaUploadDocumentResponse(documentUrl));
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new ApiError(ex.Message));
        }
    }

    [HttpPost("documents/tramitar")]
    public async Task<IActionResult> TramitarDocumento(
        GestionaTramitarDocumentoRequest request,
        CancellationToken cancellationToken)
    {
        try
        {
            await _workflow.TramitarDocumentoAsync(
                request.DocumentUrl,
                request.AssignedGroupCode,
                request.ComplaintId,
                request.IsUpdate,
                request.UpdateSource);

            return Ok(new { ok = true });
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new ApiError(ex.Message));
        }
    }

    [HttpGet("thirds/{nif}/files")]
    public async Task<ActionResult<List<ExpedienteTerceroDto>>> GetFilesByThird(
        string nif,
        [FromQuery] DateTimeOffset? desde,
        [FromQuery] DateTimeOffset? hasta,
        [FromQuery] int maxPages = 1,
        [FromQuery] int maxResults = 30,
        [FromQuery] int maxParallel = 6,
        CancellationToken cancellationToken = default)
    {
        if (string.IsNullOrWhiteSpace(nif))
        {
            return BadRequest(new ApiError("Debes indicar el NIF del tercero."));
        }

        try
        {
            var expedientes = await _gestiona.ObtenerExpedientesPorTerceroAsync(
                nif.Trim().ToUpperInvariant(),
                desde,
                hasta,
                Math.Max(1, maxPages),
                Math.Max(1, maxResults),
                Math.Max(1, maxParallel));

            return Ok(expedientes);
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new ApiError(ex.Message));
        }
    }
}
