using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using WhatsAppService.API.Application.Commands;

namespace WhatsAppService.API.Controllers;

/// <summary>
/// EN: Controller for handling WhatsApp webhooks.
/// VI: Controller để xử lý webhooks WhatsApp.
/// </summary>
[ApiController]
[Route("api/webhooks")]
[AllowAnonymous]
public class WebhooksController : ControllerBase
{
    private readonly IMediator _mediator;
    private readonly ILogger<WebhooksController> _logger;
    private readonly IConfiguration _configuration;

    public WebhooksController(
        IMediator mediator,
        ILogger<WebhooksController> logger,
        IConfiguration configuration)
    {
        _mediator = mediator;
        _logger = logger;
        _configuration = configuration;
    }

    /// <summary>
    /// EN: Webhook verification endpoint (GET).
    /// VI: Endpoint xác minh webhook (GET).
    /// </summary>
    [HttpGet("whatsapp")]
    public IActionResult VerifyWebhook(
        [FromQuery(Name = "hub.mode")] string? mode,
        [FromQuery(Name = "hub.verify_token")] string? verifyToken,
        [FromQuery(Name = "hub.challenge")] string? challenge)
    {
        _logger.LogInformation("Webhook verification request. Mode: {Mode}", mode);

        if (mode != "subscribe")
        {
            return Forbid();
        }

        var expectedToken = _configuration["WhatsApp:WebhookVerifyToken"];
        if (verifyToken != expectedToken)
        {
            _logger.LogWarning("Invalid verify token received");
            return Forbid();
        }

        _logger.LogInformation("Webhook verified successfully");
        return Ok(challenge);
    }

    /// <summary>
    /// EN: Webhook event handler (POST).
    /// VI: Handler sự kiện webhook (POST).
    /// </summary>
    [HttpPost("whatsapp")]
    public async Task<IActionResult> HandleWebhook(
        [FromHeader(Name = "X-Hub-Signature-256")] string? signature,
        [FromBody] JsonElement payload)
    {
        // EN: Verify signature
        // VI: Xác minh chữ ký
        var appSecret = _configuration["WhatsApp:AppSecret"];
        if (!string.IsNullOrEmpty(appSecret) && !string.IsNullOrEmpty(signature))
        {
            var payloadBytes = Encoding.UTF8.GetBytes(payload.GetRawText());
            var expectedSignature = ComputeHmacSha256(payloadBytes, appSecret);
            
            if (!$"sha256={expectedSignature}".Equals(signature, StringComparison.OrdinalIgnoreCase))
            {
                _logger.LogWarning("Invalid webhook signature");
                return Unauthorized();
            }
        }

        // EN: Return 200 immediately, process async
        // VI: Trả về 200 ngay lập tức, xử lý bất đồng bộ
        _ = Task.Run(async () => await ProcessWebhookAsync(payload));

        return Ok();
    }

    private async Task ProcessWebhookAsync(JsonElement payload)
    {
        try
        {
            var objectType = payload.GetProperty("object").GetString();
            if (objectType != "whatsapp_business_account")
            {
                return;
            }

            var entries = payload.GetProperty("entry");
            foreach (var entry in entries.EnumerateArray())
            {
                var changes = entry.GetProperty("changes");
                foreach (var change in changes.EnumerateArray())
                {
                    var field = change.GetProperty("field").GetString();
                    if (field != "messages")
                    {
                        continue;
                    }

                    var value = change.GetProperty("value");
                    await ProcessMessagesAsync(value);
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing webhook payload");
        }
    }

    private async Task ProcessMessagesAsync(JsonElement value)
    {
        if (!value.TryGetProperty("messages", out var messages))
        {
            return;
        }

        var metadata = value.GetProperty("metadata");
        var phoneNumberId = metadata.GetProperty("phone_number_id").GetString() ?? "";

        foreach (var message in messages.EnumerateArray())
        {
            var from = message.GetProperty("from").GetString() ?? "";
            var messageId = message.GetProperty("id").GetString() ?? "";
            var timestamp = message.GetProperty("timestamp").GetString() ?? "";
            var type = message.GetProperty("type").GetString() ?? "text";

            string? textBody = null;
            string? mediaId = null;
            string? mimeType = null;
            object? interactive = null;

            if (type == "text" && message.TryGetProperty("text", out var text))
            {
                textBody = text.GetProperty("body").GetString();
            }
            else if (type is "image" or "video" or "audio" or "document")
            {
                if (message.TryGetProperty(type, out var media))
                {
                    mediaId = media.TryGetProperty("id", out var id) ? id.GetString() : null;
                    mimeType = media.TryGetProperty("mime_type", out var mime) ? mime.GetString() : null;
                }
            }
            else if (type == "interactive" && message.TryGetProperty("interactive", out var interactiveEl))
            {
                interactive = JsonSerializer.Deserialize<object>(interactiveEl.GetRawText());
            }

            var command = new ProcessIncomingMessageCommand(
                phoneNumberId,
                from,
                messageId,
                type,
                textBody,
                mediaId,
                mimeType,
                interactive,
                DateTimeOffset.FromUnixTimeSeconds(long.Parse(timestamp)).UtcDateTime
            );

            var result = await _mediator.Send(command);
            _logger.LogInformation(
                "Message processed. Success: {Success}, ConversationId: {ConversationId}",
                result.Success, result.ConversationId);
        }
    }

    private static string ComputeHmacSha256(byte[] data, string key)
    {
        using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key));
        var hash = hmac.ComputeHash(data);
        return Convert.ToHexString(hash).ToLowerInvariant();
    }
}
