using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using PolyTraderSharp.Models;

namespace PolyTrader.Core.Persistence.Ef
{
    public class EfPositionRepository : IPositionRepository
    {
        private readonly IDbContextFactory<CoreDbContext> _factory;

        public EfPositionRepository(IDbContextFactory<CoreDbContext> factory) => _factory = factory;

        public List<Position> GetLive(int accountId)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Positions.AsNoTracking().Where(x => x.AccountId == accountId && !x.IsDemo).ToList();
        }

        public List<Position> GetDemo(int accountId)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Positions.AsNoTracking().Where(x => x.AccountId == accountId && x.IsDemo).ToList();
        }

        public Position? FindLive(int accountId, string tokenId)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Positions.AsNoTracking().FirstOrDefault(x => x.AccountId == accountId && !x.IsDemo && x.TokenId == tokenId);
        }

        public Position? FindDemo(int accountId, string tokenId)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Positions.AsNoTracking().FirstOrDefault(x => x.AccountId == accountId && x.IsDemo && x.TokenId == tokenId);
        }

        public void UpsertLive(int accountId, Position position) => Upsert(accountId, false, position);
        public void UpsertDemo(int accountId, Position position) => Upsert(accountId, true, position);

        private void Upsert(int accountId, bool isDemo, Position position)
        {
            position.AccountId = accountId;
            position.IsDemo = isDemo;

            using var ctx = _factory.CreateDbContext();
            var existing = ctx.Positions.Find(accountId, isDemo, position.TokenId);
            if (existing == null)
                ctx.Positions.Add(position);
            else
                ctx.Entry(existing).CurrentValues.SetValues(position);
            ctx.SaveChanges();
        }

        public void DeleteLive(int accountId, string tokenId) => Delete(accountId, false, tokenId);
        public void DeleteDemo(int accountId, string tokenId) => Delete(accountId, true, tokenId);

        private void Delete(int accountId, bool isDemo, string tokenId)
        {
            using var ctx = _factory.CreateDbContext();
            var existing = ctx.Positions.Find(accountId, isDemo, tokenId);
            if (existing != null)
            {
                ctx.Positions.Remove(existing);
                ctx.SaveChanges();
            }
        }

        public void DropDemo(int accountId)
        {
            using var ctx = _factory.CreateDbContext();
            var rows = ctx.Positions.Where(x => x.AccountId == accountId && x.IsDemo).ToList();
            if (rows.Count > 0)
            {
                ctx.Positions.RemoveRange(rows);
                ctx.SaveChanges();
            }
        }
    }
}
