using Api.Services.Contracts;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Models.Settings;
using Swashbuckle.AspNetCore.Annotations;
using Models.Requests;
using Common.Responses;

namespace Api.Controllers
{
    /// <summary>
    /// Endpoints that expose captcha configuration and verification.
    /// </summary>
    [ApiController]
    [Route("api/[controller]")]
    public sealed class CaptchaController : ControllerBase
    {
        private readonly CaptchaSettings _captchaSettings;
        private readonly ICaptchaVerifier _captcha;
        private readonly ILogger<CaptchaController> _log;

        public CaptchaController(IOptions<CaptchaSettings> options, ICaptchaVerifier captcha, ILogger<CaptchaController> log)
        {
            _captchaSettings = options.Value;
            _captcha = captcha;
            _log = log;
        }

        /// <summary>
        /// Returns the public reCAPTCHA site key used by the client to render the widget.
        /// </summary>
        /// <returns>200 OK with the configured public site key as a plain string.</returns>
        [HttpGet]
        [SwaggerOperation(Summary = "Get captcha public key", Description = "Returns the public reCAPTCHA site key required by the frontend to render the challenge widget.")]
        [SwaggerResponse(StatusCodes.Status200OK, "Public site key returned")]
        [ProducesResponseType(StatusCodes.Status200OK)]
        public IActionResult GetSiteKey()
        {
            return Ok(_captchaSettings.PublicKey);
        }

        /// <summary>
        /// Verifies a reCAPTCHA token submitted by the client and returns the full verification verdict.
        /// </summary>
        /// <param name="req">The verification request containing the token and optional expected action name.</param>
        /// <param name="ct">Cancellation token.</param>
        /// <returns>
        /// 200 OK with the full captcha verdict when verification passes;
        /// 400 Bad Request with an <see cref="ErrorResponse"/> if the token is missing or verification fails.
        /// </returns>
        [HttpPost("verify")]
        [SwaggerOperation(Summary = "Verify captcha token", Description = "Verifies a reCAPTCHA token and returns the provider verdict including the score.")]
        [SwaggerResponse(StatusCodes.Status200OK, "Token verified successfully")]
        [SwaggerResponse(StatusCodes.Status400BadRequest, "Token missing or verification failed", typeof(ErrorResponse))]
        [ProducesResponseType(StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> Verify([FromBody] CaptchaVerifyRequest req, CancellationToken ct)
        {
            if (req is null || string.IsNullOrWhiteSpace(req.Token))
            {
                return BadRequest(new ErrorResponse { Error = "Missing token", Code = "captcha_token_missing" });
            }

            var userIp = HttpContext.Connection.RemoteIpAddress?.ToString();
            var verdict = await _captcha.VerifyAsync(req.Token, userIp, req.ExpectedAction, ct);
            if (!verdict.Success)
            {
                _log.LogWarning("Captcha failed. ip={Ip} score={Score} err={Err}", userIp, verdict.Score, verdict.Error);
                return BadRequest(new ErrorResponse
                {
                    Error = "Captcha verification failed.",
                    Code = "captcha_verification_failed",
                    Detail = verdict.Score.HasValue ? $"Score: {verdict.Score:0.00}" : null
                });
            }

            return Ok(verdict);
        }
    }
}
