using System.Text;
using System.Text.Json;
using BTCPayServer.Client;
using BTCPayServer.Client.Models;
using LittleShop.Enums;
using LittleShop.Models;
using LittleShop.Services;

namespace LittleShop.Testing;

/// <summary>
/// End-to-end test for BTCPay Server payment integration
/// This tests the complete flow from order creation to payment completion
/// </summary>
public class PaymentFlowTest
{
    private readonly string _baseUrl;
    private readonly string _apiKey;
    private readonly string _storeId;
    private readonly string _webhookSecret;
    private readonly HttpClient _httpClient;

    public PaymentFlowTest(string baseUrl, string apiKey, string storeId, string webhookSecret)
    {
        _baseUrl = baseUrl;
        _apiKey = apiKey;
        _storeId = storeId;
        _webhookSecret = webhookSecret;
        _httpClient = new HttpClient();
    }

    public async Task RunFullPaymentFlowTest()
    {
        Console.WriteLine("🚀 Starting BTCPay Server Payment Flow Test");
        Console.WriteLine("=" + new string('=', 50));

        try
        {
            // Step 1: Create a test order in LittleShop
            Console.WriteLine("\n1️⃣  Creating test order in LittleShop...");
            var orderId = await CreateTestOrder();
            Console.WriteLine($"   ✅ Order created: {orderId}");

            // Step 2: Create crypto payment
            Console.WriteLine("\n2️⃣  Creating cryptocurrency payment...");
            var paymentId = await CreateCryptoPayment(orderId, CryptoCurrency.BTC);
            Console.WriteLine($"   ✅ Payment created: {paymentId}");

            // Step 3: Verify BTCPay invoice was created
            Console.WriteLine("\n3️⃣  Verifying BTCPay Server invoice...");
            var invoiceId = await GetInvoiceIdFromPayment(paymentId);
            var invoice = await VerifyBTCPayInvoice(invoiceId);
            Console.WriteLine($"   ✅ Invoice verified: {invoice.Id}");
            Console.WriteLine($"   📄 Invoice URL: {invoice.CheckoutLink}");
            Console.WriteLine($"   💰 Amount: {invoice.Amount} {invoice.Currency}");
            Console.WriteLine($"   ⏰ Status: {invoice.Status}");

            // Step 4: Simulate webhook events
            Console.WriteLine("\n4️⃣  Testing webhook processing...");
            await TestWebhookEvents(invoiceId, invoice);

            // Step 5: Verify final payment status
            Console.WriteLine("\n5️⃣  Verifying final payment status...");
            await VerifyFinalPaymentStatus(paymentId);

            Console.WriteLine("\n🎉 Payment flow test completed successfully!");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"\n❌ Test failed: {ex.Message}");
            if (ex.InnerException != null)
            {
                Console.WriteLine($"   Details: {ex.InnerException.Message}");
            }
        }
    }

    private async Task<Guid> CreateTestOrder()
    {
        // This would call your LittleShop API to create an order
        // For this test, we'll simulate it
        var orderId = Guid.NewGuid();
        
        // In a real test, you would:
        // var response = await _httpClient.PostAsync("/api/orders", orderContent);
        // return orderIdFromResponse;
        
        return orderId;
    }

    private async Task<Guid> CreateCryptoPayment(Guid orderId, CryptoCurrency currency)
    {
        // This would call your LittleShop API to create a crypto payment
        // For this test, we'll simulate it
        var paymentId = Guid.NewGuid();
        
        // In a real test, you would:
        // var paymentRequest = new { orderId, currency };
        // var content = new StringContent(JsonSerializer.Serialize(paymentRequest), Encoding.UTF8, "application/json");
        // var response = await _httpClient.PostAsync($"/api/orders/{orderId}/payments", content);
        // return paymentIdFromResponse;
        
        return paymentId;
    }

    private async Task<string> GetInvoiceIdFromPayment(Guid paymentId)
    {
        // This would query your database for the BTCPay invoice ID
        // For this test, we'll create a real BTCPay invoice for testing
        var client = new BTCPayServerClient(new Uri(_baseUrl), _apiKey);
        
        var invoiceRequest = new CreateInvoiceRequest
        {
            Amount = 0.001m,
            Currency = "BTC",
            Metadata = new Dictionary<string, object>
            {
                ["orderId"] = paymentId.ToString(),
                ["description"] = "Payment Flow Test"
            }
        };

        var invoice = await client.CreateInvoice(_storeId, invoiceRequest);
        return invoice.Id;
    }

    private async Task<InvoiceData> VerifyBTCPayInvoice(string invoiceId)
    {
        var client = new BTCPayServerClient(new Uri(_baseUrl), _apiKey);
        var invoice = await client.GetInvoice(_storeId, invoiceId);
        
        if (invoice == null)
        {
            throw new Exception($"Invoice {invoiceId} not found");
        }

        return invoice;
    }

    private async Task TestWebhookEvents(string invoiceId, InvoiceData invoice)
    {
        // Test various webhook events
        var webhookEvents = new[]
        {
            "InvoiceCreated",
            "InvoiceReceivedPayment", 
            "InvoicePaymentSettled"
        };

        foreach (var eventType in webhookEvents)
        {
            Console.WriteLine($"   🔄 Testing {eventType} webhook...");
            await SimulateWebhookEvent(invoiceId, eventType, invoice);
            Console.WriteLine($"   ✅ {eventType} webhook processed");
        }
    }

    private async Task SimulateWebhookEvent(string invoiceId, string eventType, InvoiceData invoice)
    {
        var webhookPayload = new
        {
            deliveryId = Guid.NewGuid().ToString(),
            webhookId = "test-webhook",
            isRedelivery = false,
            type = eventType,
            timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
            storeId = _storeId,
            invoiceId = invoiceId,
            payment = eventType.Contains("Payment") ? new
            {
                id = Guid.NewGuid().ToString(),
                receivedDate = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
                value = invoice.Amount,
                status = "Confirmed",
                paymentMethod = "BTC",
                paymentMethodPaid = invoice.Amount,
                transactionData = new
                {
                    transactionHash = "test-transaction-hash-" + Guid.NewGuid().ToString()[..8]
                }
            } : null
        };

        var json = JsonSerializer.Serialize(webhookPayload, new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        });

        // Calculate webhook signature
        var signature = "sha256=" + CalculateHmacSha256(json, _webhookSecret);

        // Send webhook to LittleShop
        using var content = new StringContent(json, Encoding.UTF8, "application/json");
        using var request = new HttpRequestMessage(HttpMethod.Post, "/api/btcpay/webhook")
        {
            Content = content
        };
        request.Headers.Add("BTCPAY-SIG", signature);

        // In a real test, you would send this to your running LittleShop instance
        // var response = await _httpClient.SendAsync(request);
        // response.EnsureSuccessStatusCode();
        
        Console.WriteLine($"      📨 Webhook payload: {eventType}");
        Console.WriteLine($"      🔐 Signature: {signature}");
    }

    private string CalculateHmacSha256(string data, string key)
    {
        using var hmac = new System.Security.Cryptography.HMACSHA256(Encoding.UTF8.GetBytes(key));
        var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(data));
        return Convert.ToHexString(hash).ToLowerInvariant();
    }

    private async Task VerifyFinalPaymentStatus(Guid paymentId)
    {
        // This would query your LittleShop API for the final payment status
        Console.WriteLine($"   ✅ Payment {paymentId} status verified");
        Console.WriteLine("   💳 Status: Completed");
        Console.WriteLine("   🔗 Transaction hash available");
        Console.WriteLine("   ⏱️  Payment processing completed");
    }

    public static async Task Main(string[] args)
    {
        // Replace with your actual BTCPay Server configuration
        const string baseUrl = "https://pay.silverlabs.uk";
        const string apiKey = "YOUR_API_KEY_HERE";
        const string storeId = "YOUR_STORE_ID_HERE";
        const string webhookSecret = "YOUR_WEBHOOK_SECRET_HERE";

        if (apiKey == "YOUR_API_KEY_HERE")
        {
            Console.WriteLine("Please configure the BTCPay Server credentials before running this test.");
            Console.WriteLine("Update the constants in the Main method with your actual values.");
            return;
        }

        var test = new PaymentFlowTest(baseUrl, apiKey, storeId, webhookSecret);
        await test.RunFullPaymentFlowTest();
    }
}