using LiteCharms.Features;
using LiteCharms.Features.MidrandBooks.AuthorBooks;
using LiteCharms.Features.MidrandBooks.Authors;
using LiteCharms.Features.MidrandBooks.Categories;
using LiteCharms.Features.MidrandBooks.Products;
using LiteCharms.Features.MidrandBooks.Products.Models;
using LiteCharms.Features.Models;

namespace MidrandBookshop.Components.Pages;

public partial class Home : ComponentBase
{
    [Inject] private ProductService ProductService { get; set; } = default!;
    [Inject] private BooksService BooksService { get; set; } = default!;
    [Inject] private AuthorService AuthorService { get; set; } = default!;
    [Inject] private CategoryService CategoryService { get; set; } = default!;
    [Inject] private NavigationManager Navigation { get; set; } = default!;

    [SupplyParameterFromQuery(Name = "q")] public string? SharedSearchQuery { get; set; }
    [SupplyParameterFromQuery] public long? AuthorId { get; set; }

    private ElementReference topTargetRef;
    public enum ViewMode { Grid, List }
    private ViewMode CurrentViewMode = ViewMode.Grid;
    private string ActiveCategory = "All";
    private bool ShowExpandedCategories = false;
    private bool ShowFilterMenu = false;
    private string SelectedSortOption = "default";
    private string ActivePriceFilter = "all";
    private bool OnlyShowNew = false;

    private List<string> MainCategories { get; set; } = ["All"];
    private List<string> DynamicExtendedCategories { get; set; } = [];

    private int ItemsPerPage = 12;
    private int VisibleCount = 12;

    private List<Product> ProductsCollection { get; set; } = [];

    protected string? ActiveAuthorFilterName { get; private set; }

    private Dictionary<long, decimal> ProductPriceCache { get; set; } = [];
    private Dictionary<long, string> ProductPrimaryCategoryCache { get; set; } = [];
    private Dictionary<long, string> ProductAuthorCache { get; set; } = [];

    private IEnumerable<Product> FilteredData
    {
        get
        {
            var data = ProductsCollection.AsEnumerable();

            if (ActiveCategory != "All" && !AuthorId.HasValue)
            {
                data = data.Where(p => ProductPrimaryCategoryCache.ContainsKey(p.Id) &&
                    ProductPrimaryCategoryCache[p.Id] == ActiveCategory);
            }

            if (!string.IsNullOrWhiteSpace(SharedSearchQuery))
            {
                var q = SharedSearchQuery.Trim();
                data = data.Where(p => (p.Name ?? "").Contains(q, StringComparison.OrdinalIgnoreCase));
            }

            if (ActivePriceFilter != "all")
            {
                data = data.Where(p =>
                {
                    var price = ProductPriceCache.TryGetValue(p.Id, out var amt) ? amt : 0m;

                    return ActivePriceFilter switch
                    {
                        "under-500" => price < 500m,
                        "500-1000" => price >= 500m && price <= 1000m,
                        "over-1000" => price > 1000m,
                        _ => true
                    };
                });
            }

            if (OnlyShowNew) data = data.Where(p => p.Enabled);

            data = SelectedSortOption switch
            {
                "price-low" => data.OrderBy(p => ProductPriceCache.TryGetValue(p.Id, out var amt) ? amt : 0m),
                "price-high" => data.OrderByDescending(p => ProductPriceCache.TryGetValue(p.Id, out var amt) ? amt : 0m),
                "title-asc" => data.OrderBy(p => p.Name ?? string.Empty, StringComparer.OrdinalIgnoreCase),
                "default" or _ => data
            };

            return data;
        }
    }

    private IEnumerable<Product> PaginatedBooks => FilteredData.Take(VisibleCount);

    private bool HasMoreItems => FilteredData.Count() > VisibleCount;

    protected override async Task OnParametersSetAsync() => await LoadCatalogDataAsync();

    private async Task LoadCatalogDataAsync()
    {
        ProductsCollection.Clear();
        ProductPriceCache.Clear();
        ProductPrimaryCategoryCache.Clear();
        ProductAuthorCache.Clear();
        ActiveAuthorFilterName = null;

        if (AuthorId.HasValue)
        {
            var authorResult = await AuthorService.GetAuthorAsync(AuthorId.Value);

            if (authorResult.IsSuccess && authorResult.Value != null)
            {
                var author = authorResult.Value;

                ActiveAuthorFilterName = author.PublisherType == PublisherTypes.Company && !string.IsNullOrWhiteSpace(author.Company)
                    ? author.Company
                    : $"{author.Name} {author.LastName}".Trim();
            }

            var authorBooksResult = await BooksService.GetBooksByAuthorAsync(AuthorId.Value);

            if (authorBooksResult.IsSuccess && authorBooksResult.Value != null)
            {
                foreach (var authorBook in authorBooksResult.Value)
                {
                    if (authorBook.Product != null)
                    {
                        var product = authorBook.Product;

                        ProductsCollection.Add(product);
                        ProductPriceCache[product.Id] = product.Price?.Amount ?? 0m;

                        ProductAuthorCache[product.Id] = ActiveAuthorFilterName ?? "Unknown Author";

                        var categoryResult = await ProductService.GetProductCategoriesAsync(product.Id);

                        ProductPrimaryCategoryCache[product.Id] = (categoryResult.IsSuccess && categoryResult.Value.Length > 0)
                            ? (categoryResult.Value[0].Name ?? "General")
                            : "General";
                    }
                }
            }
            return;
        }

        var selectionRange = new DateRange
        {
            From = new DateOnly(2020, 1, 1),
            To = DateOnly.FromDateTime(DateTime.UtcNow.AddDays(1)),
            MaxRecords = 100
        };

        var allProductsResult = await ProductService.GetProductsAsync(0, selectionRange);

        if (allProductsResult.IsSuccess && allProductsResult.Value != null)
        {
            ProductsCollection = allProductsResult.Value.ToList();

            foreach (var product in ProductsCollection)
            {
                var priceResult = await ProductService.GetProductPriceAsync(product.Id);
                ProductPriceCache[product.Id] = priceResult.IsSuccess ? priceResult.Value.Amount : 0m;

                var categoryResult = await ProductService.GetProductCategoriesAsync(product.Id);
                ProductPrimaryCategoryCache[product.Id] = (categoryResult.IsSuccess && categoryResult.Value.Length > 0)
                    ? (categoryResult.Value[0].Name ?? "General")
                    : "General";

                ProductAuthorCache[product.Id] = !string.IsNullOrWhiteSpace(product.Metadata?.Manufacturer)
                    ? product.Metadata.Manufacturer
                    : "Unknown Author";
            }
        }

        var categoriesResult = await CategoryService.GetCategoriesAsync();

        if (categoriesResult.IsSuccess && categoriesResult.Value != null)
        {
            var cleanNames = categoriesResult.Value
                .Select(c => c.Name)
                .Where(n => !string.IsNullOrEmpty(n)).Cast<string>()
                .ToList();

            MainCategories = ["All", .. cleanNames.Take(3)];
            DynamicExtendedCategories = [.. cleanNames.Skip(3)];
        }
    }

    private void ClearAuthorFilter()
    {
        var newUri = Navigation.GetUriWithQueryParameters("/", new Dictionary<string, object?> { { "authorId", null } });

        Navigation.NavigateTo(newUri);
    }

    private void ResetFilters()
    {
        SelectedSortOption = "default";
        ActivePriceFilter = "all";
        OnlyShowNew = false;
        VisibleCount = ItemsPerPage;
    }

    private void NavigateToProduct(long id) => Navigation.NavigateTo($"/product/{id}");
    private void SetViewMode(ViewMode targetMode) => CurrentViewMode = targetMode;

    private void SelectCategory(string categoryName)
    {
        ActiveCategory = categoryName;
        VisibleCount = ItemsPerPage;

        var updatedUri = Navigation.GetUriWithQueryParameters(Navigation.Uri, new Dictionary<string, object?> {{ "q", null }});

        Navigation.NavigateTo(updatedUri);
    }

    private void ToggleExtraCategories() => ShowExpandedCategories = !ShowExpandedCategories;
    private void ToggleFilterMenu() => ShowFilterMenu = !ShowFilterMenu;
    private void ChangeSort(string sortOption) => SelectedSortOption = sortOption;
    private void ChangePriceFilter(string priceBracket) { ActivePriceFilter = priceBracket; VisibleCount = ItemsPerPage; }
    private void ToggleNewArrivalsOnly(ChangeEventArgs e) { OnlyShowNew = e.Value is bool b && b; VisibleCount = ItemsPerPage; }
    private void LoadNextPage() { if (HasMoreItems) VisibleCount += ItemsPerPage; }
}