using Mango.Nop.Core.Repositories;
using Nop.Core;
using Nop.Core.Caching;
using Nop.Data;
using Nop.Plugin.Misc.AuctionPlugin.Domains.DataLayer.Interfaces;
using Nop.Plugin.Misc.AuctionPlugin.Domains.Entities;
using Nop.Services.Catalog;
using System;
using Nop.Plugin.Misc.AuctionPlugin.Services;
using Nop.Services.Logging;

namespace Nop.Plugin.Misc.AuctionPlugin.Domains.DataLayer;

public class AuctionDbContext : MgDbContextBase, IAuctionDbSet<AuctionDbTable>, IProductToAuctionDbSet<ProductToAuctionDbTable>, IAuctionBidDbSet<AuctionBidDbTable>
{
    private readonly IProductService _productService;
    private readonly IStaticCacheManager _staticCacheManager;

    public AuctionDbTable Auctions { get; set; }
    public ProductToAuctionDbTable ProductToAuctions { get; set; }
    public AuctionBidDbTable AuctionBids { get; set; }


    //public EntityRepository<Auction> Auctions2 { get; set; }
    //public IRepository<AuctionBid> AuctionBids2 { get; set; }


    public AuctionDbContext(INopDataProvider dataProvider, AuctionDbTable auctionDbTable, ProductToAuctionDbTable productToAuctionDbTable, AuctionBidDbTable auctionBidDbTable, IProductService productService, IStaticCacheManager staticCacheManager, ILogger logger) : base(dataProvider, logger)
    {
        _productService = productService;
        _staticCacheManager = staticCacheManager;

        Auctions = auctionDbTable;
        ProductToAuctions = productToAuctionDbTable;
        AuctionBids = auctionBidDbTable;

        //Auctions.Table
        //var auctions = DataProvider.GetTable<Auction>().Where(x => x.Closed);
    }

    //public AuctionDbContext(IRepository<Auction> _auctionRepository, IRepository<AuctionBid> _auctionBidRepository)
    //{
    //    Auctions2 = _auctionRepository as EntityRepository<Auction>;
    //    AuctionBids2 = _auctionBidRepository;
    //}

    public Task<List<AuctionBid>> GetAllLastBidByAuctionIdAsync(int auctionId) => AuctionBids.GetAllLastBidByAuctionId(auctionId).ToListAsync();

    public Task<Dictionary<int, AuctionBid>> GetAllLastBidDictionaryByAuctionIdAsync(int auctionId)
        => AuctionBids.GetAllLastBidByAuctionId(auctionId).ToDictionaryAsync(x => x.ProductAuctionMappingId);

    public async Task<List<ProductToAuctionMapping>> GetProductToAuctionsByProductIdAsync(int productId)
    {
        return [..await ProductToAuctions.GetByProductId(productId).ToListAsync()];
    }

    public async Task<List<ProductToAuctionMapping>> GetProductToAuctionByAuctionIdAndProductIdAsync(int auctionId, int productId, bool activeProductOnly)
    {
        return [..await ProductToAuctions.GetByAuctionAndProductId(auctionId, productId, activeProductOnly).ToListAsync()];
    }

    public Task<bool> HasBidByProductToAuctionIdAsync(int productToAuctionId)
        => AuctionBids.HasBidByProductToAuctionIdAsync(productToAuctionId);

    public Task<AuctionBid> GetLastAuctionBidByProductToAuctionId(int productToAuctionId)
        => AuctionBids.GetLastAuctionBidByProductToAuctionId(productToAuctionId).FirstOrDefaultAsync();

    public Task<int> GetBidsCountByProductToAuctionIdAsync(int productToAuctionId)
        => AuctionBids.GetBidsCountByProductToAuctionIdAsync(productToAuctionId);


    public Task<AuctionBid> RevertAuctionBidByProductToAuctionId(int productToAuctionId)
        => AuctionBids.RevertByProductToAuctionIdAsync(productToAuctionId);

    //public async Task ResetProductToAuctionByProductId(int productId)
    //    => await ResetProductToAuctionAsync(await ProductToAuctions.GetByProductId(productId).FirstOrDefaultAsync());

    public async Task ResetProductToAuctionByIdAsync(int productToAuctionId, decimal basePrice = 0)
        => await ResetProductToAuctionAsync(ProductToAuctions.GetById(productToAuctionId), basePrice);

    public async Task ResetProductToAuctionAsync(ProductToAuctionMapping productToAuction, decimal basePrice = 0)
    {
        if (productToAuction == null)
        {
            Logger.Error($"AuctionDbContext.ResetProductToAuctionAsync(); productToAuction == null");
            return;
        }

        await Logger.InformationAsync($"AuctionDbContext.ResetProductToAuctionAsync(); productToAuction.Id: {productToAuction.Id}; basePrice: {basePrice}");

        var product = await _productService.GetProductByIdAsync(productToAuction.ProductId);
        if (product == null)
        {
            Logger.Error($"AuctionDbContext.ResetProductToAuctionAsync(); product == null");
            return;
        }

        if (basePrice <= 0) basePrice = product.Price;
        else
        {
            product.Price = basePrice;
            await _productService.UpdateProductAsync(product);
        }

        await ProductToAuctions.ResetAsync(productToAuction, basePrice);
        await AuctionBids.DeleteAllByProductToAuctionIdAsync(productToAuction.Id);

        await _staticCacheManager.ClearAsync();
        //await _staticCacheManager.RemoveByPrefixAsync(AUCTION_PATTERN_KEY);
    }
}