using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using PolyTrader.Modules.ResolutionFarming.Models;

namespace PolyTrader.Modules.ResolutionFarming.Persistence.Ef
{
    public class EfRfSettingsRepository : IRfSettingsRepository
    {
        private readonly IDbContextFactory<ResolutionFarmingDbContext> _factory;
        public EfRfSettingsRepository(IDbContextFactory<ResolutionFarmingDbContext> factory) => _factory = factory;

        public List<RfSettings> GetAll()
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Settings.AsNoTracking().ToList();
        }

        public RfSettings? Get(int accountId)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Settings.AsNoTracking().FirstOrDefault(s => s.AccountId == accountId);
        }

        public void Upsert(RfSettings settings)
        {
            using var ctx = _factory.CreateDbContext();
            bool exists = ctx.Settings.Any(s => s.AccountId == settings.AccountId);
            if (exists) ctx.Settings.Update(settings);
            else ctx.Settings.Add(settings);
            ctx.SaveChanges();
        }
    }

    public class EfRfCandidateRepository : IRfCandidateRepository
    {
        private readonly IDbContextFactory<ResolutionFarmingDbContext> _factory;
        public EfRfCandidateRepository(IDbContextFactory<ResolutionFarmingDbContext> factory) => _factory = factory;

        public void Insert(RfCandidate candidate)
        {
            using var ctx = _factory.CreateDbContext();
            ctx.Candidates.Add(candidate);
            ctx.SaveChanges();
        }

        public List<RfCandidate> GetRecent(int accountId, int limit)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Candidates.AsNoTracking()
                .Where(c => c.AccountId == accountId)
                .OrderByDescending(c => c.ScannedAt)
                .Take(limit)
                .ToList();
        }
    }

    public class EfRfPositionRepository : IRfPositionRepository
    {
        private readonly IDbContextFactory<ResolutionFarmingDbContext> _factory;
        public EfRfPositionRepository(IDbContextFactory<ResolutionFarmingDbContext> factory) => _factory = factory;

        public List<RfPosition> GetOpen(int accountId)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Positions.AsNoTracking().Where(p => p.AccountId == accountId).ToList();
        }

        public List<RfPosition> GetAllOpen()
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Positions.AsNoTracking().ToList();
        }

        public RfPosition? Find(int accountId, string tokenId)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Positions.AsNoTracking().FirstOrDefault(p => p.AccountId == accountId && p.TokenId == tokenId);
        }

        public void Upsert(RfPosition position)
        {
            using var ctx = _factory.CreateDbContext();
            bool exists = ctx.Positions.Any(p => p.AccountId == position.AccountId && p.TokenId == position.TokenId);
            if (exists) ctx.Positions.Update(position);
            else ctx.Positions.Add(position);
            ctx.SaveChanges();
        }

        public void Delete(int accountId, string tokenId)
        {
            using var ctx = _factory.CreateDbContext();
            var row = ctx.Positions.FirstOrDefault(p => p.AccountId == accountId && p.TokenId == tokenId);
            if (row != null) { ctx.Positions.Remove(row); ctx.SaveChanges(); }
        }

        public int CountOpenedSince(int accountId, DateTime since)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Positions.AsNoTracking().Count(p => p.AccountId == accountId && p.OpenedAt >= since);
        }
    }

    public class EfRfClosedTradeRepository : IRfClosedTradeRepository
    {
        private readonly IDbContextFactory<ResolutionFarmingDbContext> _factory;
        public EfRfClosedTradeRepository(IDbContextFactory<ResolutionFarmingDbContext> factory) => _factory = factory;

        public void Insert(RfClosedTrade trade)
        {
            using var ctx = _factory.CreateDbContext();
            ctx.ClosedTrades.Add(trade);
            ctx.SaveChanges();
        }

        public List<RfClosedTrade> Find(Expression<Func<RfClosedTrade, bool>> predicate)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.ClosedTrades.AsNoTracking().Where(predicate).ToList();
        }

        public decimal RealizedPnlSince(int accountId, DateTime since)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.ClosedTrades.AsNoTracking()
                .Where(t => t.AccountId == accountId && t.ClosedAt >= since)
                .Select(t => (decimal?)t.RealizedPnl)
                .Sum() ?? 0m;
        }
    }
}
