using LiteCharms.Features.Api.Configuration;
using LiteCharms.Features.Hasher;
using LiteCharms.Features.MidrandBooks.AuthorBooks;
using LiteCharms.Features.MidrandBooks.Orders;
using LiteCharms.Features.MidrandBooks.Orders.Models;
using LiteCharms.Features.MidrandBooks.Payments;
using LiteCharms.Features.MidrandBooks.Payments.Models;

namespace MidrandBookshop.Components.Pages;

public partial class Checkout()
{
    [Inject] public HashService HashService { get; set; } = default!;
    [Inject] public PaymentService PaymentService { get; set; } = default!;
    [Inject] public OrderService OrderService { get; set; } = default!;
    [Inject] public BooksService BooksService { get; set; } = default!;
    [Inject] public CartService CartService { get; set; } = default!;
    [Inject] public PayfastService PayfastService { get; set; } = default!;
    [Inject] public IOptions<PayfastSettings> PayfastOptions { get; set; } = default!;
    [Inject] private AuthenticationStateProvider AuthStateProvider { get; set; } = default!;
    [Inject] public IJSRuntime JSRuntime { get; set; } = default!;
    [Inject] private HydrationService HydrationService { get; set; } = default!;
    [Inject] private CancellationToken CancellationToken { get; set; } = default!;

    private Cart ShoppingCart => CartService.ShoppingCart;
    private ClaimsPrincipal? User { get; set; }
    private bool IsProcessing { get; set; }

    private decimal ShippingCost = 0;
    private bool IsSameAddress = true;

    private Dictionary<string, string> CheckoutPayload { get; set; } = [];

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthStateProvider.GetAuthenticationStateAsync();
        User = authState!.User;

        Navigation.LocationChanged += OnLocationChanged;
        CartService.OnCartChanged += CartService_OnCartChanged;

        await CartService.LoadCartFromStorageAsync();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender == false && HydrationService.CartHydrated == false)
        {
            await HydrationService.EnsureCustomerExistsAsync(CancellationToken);
            await HydrationService.RehydrateCartFromPendingOrderAsync(CancellationToken);

            CartService.NotifyStateChanged();
        }
    }

    private async void CartService_OnCartChanged() => await InvokeAsync(StateHasChanged);

    private void OnLocationChanged(object? sender, LocationChangedEventArgs e) => StateHasChanged();

    private async Task ChangeQuantity(CartItem item, int delta)
    {
        var peekQuantity = item.Quantity + delta;

        if (peekQuantity < 1) return;

        CartService.UpdateQuantity(item.Price!.Id, delta);

        await CartService.SaveCartToStorageAsync();
    }

    private async Task RemoveFromCart(CartItem item)
    {
        CartService.RemoveOneItem(item.Price!.Id);

        await CartService.SaveCartToStorageAsync();
    }

    private async Task PayNow(MouseEventArgs args)
    {
        if (IsProcessing) return;

        try
        {
            IsProcessing = true;

            StateHasChanged();

            Result<long> orderResult;

            var customerId = (long)ShoppingCart.CustomerId!;

            if (!ShoppingCart.OrderId.HasValue)
            {
                CreateOrder request = new(ShoppingCart.TotalAmount, null);

                orderResult = await OrderService.CreateOrderAsync(customerId, request, CancellationToken);
                ShoppingCart.OrderId = orderResult.Value;
            }

            List<CreateOrderItem> orderItems = [];

            var orderId = (long)ShoppingCart.OrderId;

            await OrderService.ClearOrderItemsAsync(orderId, CancellationToken);

            foreach (var item in ShoppingCart.Items)
            {
                var bookRequest = await BooksService.GetBookByProductIdAsync(item.Price!.Id, CancellationToken);

                if (bookRequest.IsSuccess)
                {
                    var orderItem = new CreateOrderItem(bookRequest.Value.Id, item.Price.Id, item.Quantity);
                    orderItems.Add(orderItem);
                }
            }

            var orderHash = HashService.HashEncodeLongId(orderId).Value;
            var paymentGen = await PaymentService.CreatePaymentAsync(ShoppingCart.TotalAmount, orderId, orderHash, CancellationToken);

            CreateLedgerEntry ledgerRequest = new()
            {
                OrderId = orderId,
                CustomerId = customerId,
                PaymentGatewayId = 1, // TODO: lookup value to match user selection
                PaymentGatewayReference = orderHash,
                PaymentId = paymentGen.Value,
                Status = LiteCharms.Features.LedgerStatuses.Sent,
            };
            await PaymentService.WriteLedgerEntryAsync(ledgerRequest, CancellationToken);

            var addItemsResult = await OrderService.AddItemsToOrderAsync(orderId, [.. orderItems], CancellationToken);
            var hostAddress = Navigation.BaseUri.TrimEnd('/');

            CheckoutPayload = new Dictionary<string, string>
            {
                { "merchant_id", PayfastOptions.Value.MerchantId! },
                { "merchant_key", PayfastOptions.Value.MerchantKey! },
                { "return_url", $"{hostAddress}/payment-success" },
                { "cancel_url", $"{hostAddress}/payment-failed" },
                { "notify_url", "https://api.uat.midrandbooks.co.za/v1/payments/payfast/confirm" },
                { "email_address", User?.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Email)!.Value! },
                { "m_payment_id", orderHash },
                { "amount", ShoppingCart.TotalAmount.ToString("F2", CultureInfo.InvariantCulture) },
                { "item_name", "MidrandBooks Sale" },
            };

            var signature = PayfastService.GenerateSignature(CheckoutPayload!, PayfastOptions.Value.Passphrase).Value;
            CheckoutPayload.Add("signature", signature);

            StateHasChanged();

            await JSRuntime.InvokeVoidAsync("eval", "document.getElementById('payfastForm').submit();");
        }
        catch
        {
            IsProcessing = false;
            StateHasChanged();
        }
    }
}
