using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using QRRapidoApp.Filters;
using QRRapidoApp.Models.DTOs;
using QRRapidoApp.Models.ViewModels;
using QRRapidoApp.Services;

namespace QRRapidoApp.Controllers
{
    /// <summary>
    /// QRRapido public API v1 — generate QR codes programmatically.
    /// Authenticate with your API key using the <c>X-API-Key</c> header.
    /// Get your key at <c>https://qrrapido.site/Developer</c>.
    /// </summary>
    [ApiController]
    [Route("api/v1/[controller]")]
    [EnableCors("ApiPolicy")]
    [ApiKeyAuthorize]
    [Produces("application/json")]
    public class QRManagerController : ControllerBase
    {
        private readonly IQRBusinessManager _qrBusinessManager;
        private readonly ILogger<QRManagerController> _logger;

        private static readonly HashSet<string> _validFormats = new(StringComparer.OrdinalIgnoreCase)
            { "png", "webp", "svg" };

        private static readonly HashSet<string> _validTypes = new(StringComparer.OrdinalIgnoreCase)
            { "url", "pix", "wifi", "vcard", "whatsapp", "email", "sms", "texto" };

        public QRManagerController(IQRBusinessManager qrBusinessManager, ILogger<QRManagerController> logger)
        {
            _qrBusinessManager = qrBusinessManager;
            _logger = logger;
        }

        /// <summary>Health check — no API key required.</summary>
        [HttpGet("ping")]
        [AllowAnonymous]
        [ProducesResponseType(StatusCodes.Status200OK)]
        public IActionResult Ping() =>
            Ok(new { status = "QRRapido API v1 is up", timestamp = DateTime.UtcNow });

        /// <summary>Validate API key and return plan info.</summary>
        [HttpGet("me")]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status401Unauthorized)]
        public IActionResult Me()
        {
            var userId = HttpContext.Items["ApiKeyUserId"] as string;
            var prefix = HttpContext.Items["ApiKeyPrefix"] as string;
            var tier   = HttpContext.Items["ApiPlanTier"];
            return Ok(new { userId, prefix, plan = tier?.ToString(), valid = true });
        }

        /// <summary>
        /// Generate a QR code and receive it as a base64-encoded image.
        /// </summary>
        /// <remarks>
        /// Supported output formats: **png** (default), **webp** (recommended — ~40% smaller), **svg**.
        ///
        /// Rate limits and monthly quotas are returned in response headers:
        /// `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset`, `X-Quota-Limit`, `X-Quota-Remaining`.
        /// </remarks>
        /// <response code="200">QR code generated successfully.</response>
        /// <response code="400">Invalid request parameters.</response>
        /// <response code="401">Missing or invalid API key.</response>
        /// <response code="402">Insufficient credits.</response>
        /// <response code="429">Rate limit or monthly quota exceeded.</response>
        /// <response code="500">Internal server error.</response>
        [HttpPost("generate")]
        [ProducesResponseType(typeof(QRResponseDto), StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(object), StatusCodes.Status400BadRequest)]
        [ProducesResponseType(typeof(object), StatusCodes.Status401Unauthorized)]
        [ProducesResponseType(typeof(object), StatusCodes.Status402PaymentRequired)]
        [ProducesResponseType(typeof(object), StatusCodes.Status429TooManyRequests)]
        public async Task<IActionResult> Generate([FromBody] QRGenerationRequest request)
        {
            // Input validation
            if (string.IsNullOrWhiteSpace(request.Content))
                return BadRequest(new { error = "Field 'content' is required." });

            if (request.Content.Length > 2048)
                return BadRequest(new { error = "Field 'content' exceeds the maximum length of 2048 characters." });

            var format = (request.OutputFormat ?? "png").ToLowerInvariant();
            if (!_validFormats.Contains(format))
                return BadRequest(new { error = $"Invalid 'outputFormat'. Allowed values: {string.Join(", ", _validFormats)}." });

            var type = (request.Type ?? "url").ToLowerInvariant();
            if (!_validTypes.Contains(type))
                return BadRequest(new { error = $"Invalid 'type'. Allowed values: {string.Join(", ", _validTypes)}." });

            request.OutputFormat = format;
            request.Type = type;

            var userId = HttpContext.Items["ApiKeyUserId"] as string;
            var context = new UserRequesterContext
            {
                UserId           = userId,
                IpAddress        = HttpContext.Connection.RemoteIpAddress?.ToString() ?? "api",
                IsApiKeyRequest  = true
            };

            var result = await _qrBusinessManager.ProcessGenerationAsync(request, context);

            if (!result.Success)
            {
                return result.ErrorCode switch
                {
                    "INSUFFICIENT_CREDITS" => StatusCode(402, result),
                    _ => BadRequest(result)
                };
            }

            // Map format and mimeType into the response
            result.Format   = format;
            result.MimeType = format switch
            {
                "webp" => "image/webp",
                "svg"  => "image/svg+xml",
                _      => "image/png"
            };

            return Ok(result);
        }

        /// <summary>
        /// Smoke-test endpoint — generates a QR code without an API key (GET, for quick browser testing).
        /// </summary>
        [HttpGet("generate-get-test")]
        [AllowAnonymous]
        [ApiExplorerSettings(IgnoreApi = true)] // Hidden from Swagger docs
        public async Task<IActionResult> GenerateGetTest(
            string content = "https://qrrapido.site",
            string color   = "000000",
            string format  = "png")
        {
            var request = new QRGenerationRequest
            {
                Content      = content,
                PrimaryColor = "#" + color.Replace("#", ""),
                Type         = "url",
                Size         = 400,
                OutputFormat = format
            };

            var context = new UserRequesterContext
            {
                UserId    = "browser-test",
                IpAddress = HttpContext.Connection.RemoteIpAddress?.ToString()
            };

            var result = await _qrBusinessManager.ProcessGenerationAsync(request, context);
            if (!result.Success) return BadRequest(result.Message);

            byte[] imageBytes = Convert.FromBase64String(result.QRCodeBase64!);
            var mimeType = format == "webp" ? "image/webp" : "image/png";
            return File(imageBytes, mimeType);
        }
    }
}
