using CMSMicroservice.Protobuf.Protos.DiscountShoppingCart;
using Blazored.LocalStorage;

namespace FrontOffice.Main.Utilities;

public record DiscountCartItem(
    long ProductId,
    string Title,
    string ImageUrl,
    long UnitPrice,
    int MaxDiscountPercent,
    int Quantity,
    long TotalPrice,
    long DiscountAmount,
    long FinalPrice,
    int RemainingCount);

public class DiscountCartService
{
    private readonly DiscountShoppingCartContract.DiscountShoppingCartContractClient _client;
    private readonly ILocalStorageService _localStorage;
    private readonly List<DiscountCartItem> _items = new();
    private const string TokenStorageKey = "auth:token";
    private bool _isInitialized;

    public event Action? OnChange;

    public DiscountCartService(
        DiscountShoppingCartContract.DiscountShoppingCartContractClient client,
        ILocalStorageService localStorage)
    {
        _client = client;
        _localStorage = localStorage;
    }

    public IReadOnlyList<DiscountCartItem> Items => _items.AsReadOnly();
    public long TotalPrice => _items.Sum(i => i.TotalPrice);
    public long TotalDiscount => _items.Sum(i => i.DiscountAmount);
    public long FinalPrice => _items.Sum(i => i.FinalPrice);
    public int Count => _items.Sum(i => i.Quantity);

    public async Task AddAsync(long productId, int count = 1)
    {
        if (!await IsAuthenticatedAsync()) return;
        try
        {
            await _client.AddToCartAsync(new AddToCartRequest
            {
                ProductId = productId,
                Count = count
            });
            await LoadFromServerAsync();
        }
        catch { /* best-effort */ }
    }

    public async Task UpdateQuantityAsync(long productId, int newCount)
    {
        if (!await IsAuthenticatedAsync()) return;
        if (newCount <= 0)
        {
            await RemoveAsync(productId);
            return;
        }
        try
        {
            await _client.UpdateCartItemCountAsync(new UpdateCartItemCountRequest
            {
                ProductId = productId,
                NewCount = newCount
            });
            await LoadFromServerAsync();
        }
        catch { /* best-effort */ }
    }

    public async Task RemoveAsync(long productId)
    {
        if (!await IsAuthenticatedAsync()) return;
        try
        {
            await _client.RemoveFromCartAsync(new RemoveFromCartRequest
            {
                ProductId = productId
            });
            _items.RemoveAll(i => i.ProductId == productId);
            Notify();
        }
        catch { /* best-effort */ }
    }

    public async Task ClearAsync()
    {
        if (!await IsAuthenticatedAsync()) return;
        try
        {
            await _client.ClearCartAsync(new ClearCartRequest());
            _items.Clear();
            Notify();
        }
        catch { /* best-effort */ }
    }

    public async Task EnsureInitializedAsync()
    {
        if (_isInitialized) return;
        if (await IsAuthenticatedAsync())
        {
            await LoadFromServerAsync();
        }
        _isInitialized = true;
    }

    private async Task LoadFromServerAsync()
    {
        if (!await IsAuthenticatedAsync()) return;
        try
        {
            var response = await _client.GetUserCartAsync(new GetUserCartRequest());
            _items.Clear();
            foreach (var item in response.Items)
            {
                _items.Add(new DiscountCartItem(
                    ProductId: item.ProductId,
                    Title: item.ProductTitle ?? string.Empty,
                    ImageUrl: item.ProductImagePath,
                    UnitPrice: item.UnitPrice,
                    MaxDiscountPercent: item.MaxDiscountPercent,
                    Quantity: item.Count,
                    TotalPrice: item.TotalPrice,
                    DiscountAmount: item.DiscountAmount,
                    FinalPrice: item.FinalPrice,
                    RemainingCount: item.ProductRemainingCount));
            }
            Notify();
        }
        catch { /* fallback to local state */ }
    }

    private void Notify() => OnChange?.Invoke();

    private async Task<bool> IsAuthenticatedAsync()
    {
        try
        {
            var token = await _localStorage.GetItemAsync<string>(TokenStorageKey);
            return !string.IsNullOrWhiteSpace(token);
        }
        catch { return false; }
    }
}
