using Microsoft.AspNetCore.Mvc;
using OnlyOneAccessTemplate.Services;

namespace OnlyOneAccessTemplate.Controllers
{
    [Route("api/modules")]
    public class DynamicProxyController : ControllerBase
    {
        private readonly IModuleService _moduleService;
        private readonly HttpClient _httpClient;
        private readonly IRateLimitService _rateLimitService;
        private readonly ILogger<DynamicProxyController> _logger;

        public DynamicProxyController(
            IModuleService moduleService,
            HttpClient httpClient,
            IRateLimitService rateLimitService,
            ILogger<DynamicProxyController> logger)
        {
            _moduleService = moduleService;
            _httpClient = httpClient;
            _rateLimitService = rateLimitService;
            _logger = logger;
        }

        [HttpPost("{moduleId}/{action}")]
        [HttpGet("{moduleId}/{action}")]
        [HttpPut("{moduleId}/{action}")]
        [HttpDelete("{moduleId}/{action}")]
        public async Task<IActionResult> ProxyRequest(string moduleId, string action)
        {
            try
            {
                // Buscar configuração do módulo
                var module = await _moduleService.GetModuleConfigAsync(moduleId);
                if (module == null || !module.IsActive)
                {
                    return NotFound(new { success = false, message = "Módulo não encontrado ou inativo" });
                }

                // Rate limiting
                var clientIP = GetClientIP();
                await _rateLimitService.RecordRequestAsync(clientIP);

                if (await _rateLimitService.ShouldShowCaptchaAsync(clientIP))
                {
                    return StatusCode(429, new
                    {
                        success = false,
                        message = "Rate limit exceeded",
                        requiresCaptcha = true
                    });
                }

                // Verificar se o endpoint existe no mapeamento
                if (!module.ProxyMappings.ContainsKey(action))
                {
                    return NotFound(new { success = false, message = $"Ação '{action}' não disponível para este módulo" });
                }

                var targetUrl = module.ProxyMappings[action];

                // Preparar requisição
                var requestMessage = new HttpRequestMessage(
                    new HttpMethod(Request.Method),
                    targetUrl + Request.QueryString);

                // Copiar headers necessários
                foreach (var header in module.Headers)
                {
                    requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value);
                }

                // Copiar corpo da requisição se necessário
                if (Request.ContentLength > 0)
                {
                    requestMessage.Content = new StreamContent(Request.Body);
                    if (Request.ContentType != null)
                    {
                        requestMessage.Content.Headers.TryAddWithoutValidation("Content-Type", Request.ContentType);
                    }
                }

                _logger.LogInformation("Proxying {Method} request to {ModuleId}.{Action} -> {TargetUrl}",
                    Request.Method, moduleId, action, targetUrl);

                // Fazer requisição
                var response = await _httpClient.SendAsync(requestMessage);
                var responseContent = await response.Content.ReadAsStringAsync();

                // Retornar resposta
                Response.StatusCode = (int)response.StatusCode;

                if (response.Content.Headers.ContentType?.MediaType != null)
                {
                    Response.ContentType = response.Content.Headers.ContentType.MediaType;
                }

                return Content(responseContent);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Erro no proxy para {ModuleId}.{Action}", moduleId, action);
                return StatusCode(500, new { success = false, message = "Erro interno do servidor" });
            }
        }

        private string GetClientIP()
        {
            return HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown";
        }
    }
}