using Asp.Versioning;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using FacebookService.API.Application.Commands;
using System.Security.Cryptography;
using System.Text;

namespace FacebookService.API.Controllers;

/// <summary>
/// EN: Controller for Facebook Messenger webhooks.
/// VI: Controller cho Facebook Messenger webhooks.
/// </summary>
[ApiController]
[Route("api/webhooks/facebook")]
[Produces("application/json")]
[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 ?? throw new ArgumentNullException(nameof(mediator));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
    }

    /// <summary>
    /// EN: Webhook verification endpoint for Facebook.
    /// VI: Endpoint xác thực webhook cho Facebook.
    /// </summary>
    [HttpGet]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status403Forbidden)]
    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 received");

        var expectedToken = _configuration["Facebook:VerifyToken"] 
            ?? _configuration["FACEBOOK_VERIFY_TOKEN"];

        if (mode == "subscribe" && verifyToken == expectedToken)
        {
            _logger.LogInformation("Webhook verified successfully");
            return Ok(challenge);
        }

        _logger.LogWarning("Webhook verification failed: invalid token");
        return Forbid();
    }

    /// <summary>
    /// EN: Receive webhook events from Facebook Messenger.
    /// VI: Nhận webhook events từ Facebook Messenger.
    /// </summary>
    [HttpPost]
    [ProducesResponseType(StatusCodes.Status200OK)]
    [ProducesResponseType(StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> ReceiveWebhook([FromBody] FacebookWebhookPayload payload)
    {
        _logger.LogInformation("Webhook event received: {Object}", payload?.Object);

        // EN: Verify signature if configured / VI: Xác thực signature nếu được cấu hình
        var appSecret = _configuration["Facebook:AppSecret"] ?? _configuration["FACEBOOK_APP_SECRET"];
        if (!string.IsNullOrEmpty(appSecret))
        {
            var signature = Request.Headers["X-Hub-Signature-256"].FirstOrDefault();
            if (!await VerifySignatureAsync(appSecret, signature))
            {
                _logger.LogWarning("Invalid webhook signature");
                return BadRequest(new { error = "Invalid signature" });
            }
        }

        if (payload?.Object != "page")
        {
            return Ok("EVENT_RECEIVED");
        }

        // EN: Process each entry / VI: Xử lý từng entry
        foreach (var entry in payload.Entry ?? Enumerable.Empty<WebhookEntry>())
        {
            foreach (var messaging in entry.Messaging ?? Enumerable.Empty<MessagingEvent>())
            {
                if (messaging.Message != null)
                {
                    await ProcessMessageAsync(entry.Id, messaging);
                }
                else if (messaging.Postback != null)
                {
                    await ProcessPostbackAsync(entry.Id, messaging);
                }
            }
        }

        // EN: Return 200 quickly to avoid timeout / VI: Trả về 200 nhanh để tránh timeout
        return Ok("EVENT_RECEIVED");
    }

    private async Task ProcessMessageAsync(string pageId, MessagingEvent messaging)
    {
        try
        {
            var command = new ProcessIncomingMessageCommand(
                PageId: pageId,
                SenderId: messaging.Sender?.Id ?? "",
                MessageText: messaging.Message?.Text ?? "",
                FacebookMessageId: messaging.Message?.Mid,
                Timestamp: messaging.Timestamp,
                QuickReplyPayload: messaging.Message?.QuickReply?.Payload
            );

            var result = await _mediator.Send(command);

            _logger.LogInformation(
                "Message processed: ConversationId={ConversationId}, IsNew={IsNew}",
                result.ConversationId, result.IsNewConversation);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing message from sender: {SenderId}", 
                messaging.Sender?.Id);
        }
    }

    private async Task ProcessPostbackAsync(string pageId, MessagingEvent messaging)
    {
        try
        {
            var command = new ProcessIncomingMessageCommand(
                PageId: pageId,
                SenderId: messaging.Sender?.Id ?? "",
                MessageText: messaging.Postback?.Title ?? "",
                QuickReplyPayload: messaging.Postback?.Payload
            );

            await _mediator.Send(command);

            _logger.LogInformation("Postback processed for sender: {SenderId}", 
                messaging.Sender?.Id);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error processing postback from sender: {SenderId}", 
                messaging.Sender?.Id);
        }
    }

    private async Task<bool> VerifySignatureAsync(string appSecret, string? signature)
    {
        if (string.IsNullOrEmpty(signature))
            return false;

        // EN: Read raw body / VI: Đọc raw body
        Request.Body.Position = 0;
        using var reader = new StreamReader(Request.Body, Encoding.UTF8, leaveOpen: true);
        var body = await reader.ReadToEndAsync();
        Request.Body.Position = 0;

        // EN: Calculate expected signature / VI: Tính signature mong đợi
        using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(appSecret));
        var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(body));
        var expectedSignature = "sha256=" + BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();

        return signature == expectedSignature;
    }
}

#region Webhook Payload Models

/// <summary>
/// EN: Facebook webhook payload model.
/// VI: Model payload webhook Facebook.
/// </summary>
public record FacebookWebhookPayload
{
    public string? Object { get; init; }
    public List<WebhookEntry>? Entry { get; init; }
}

public record WebhookEntry
{
    public string Id { get; init; } = "";
    public long Time { get; init; }
    public List<MessagingEvent>? Messaging { get; init; }
}

public record MessagingEvent
{
    public Sender? Sender { get; init; }
    public Recipient? Recipient { get; init; }
    public long Timestamp { get; init; }
    public MessagePayload? Message { get; init; }
    public PostbackPayload? Postback { get; init; }
}

public record Sender { public string? Id { get; init; } }
public record Recipient { public string? Id { get; init; } }

public record MessagePayload
{
    public string? Mid { get; init; }
    public string? Text { get; init; }
    public QuickReplyPayload? QuickReply { get; init; }
    public List<AttachmentPayload>? Attachments { get; init; }
}

public record QuickReplyPayload { public string? Payload { get; init; } }
public record PostbackPayload 
{ 
    public string? Title { get; init; }
    public string? Payload { get; init; } 
}
public record AttachmentPayload
{
    public string? Type { get; init; }
    public AttachmentInnerPayload? Payload { get; init; }
}
public record AttachmentInnerPayload { public string? Url { get; init; } }

#endregion
