using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using PolyTraderSharp.Models;

namespace PolyTrader.Modules.CopyTrading.Persistence.Ef
{
    /// <summary>
    /// EF-Core-Kontext für die Entitäten des Copytrading-Moduls (gleiche MySQL-DB wie der
    /// Core, eigene Tabellen mit Präfix mod_copytrading_).
    /// </summary>
    public class CopyTradingDbContext : DbContext
    {
        public CopyTradingDbContext(DbContextOptions<CopyTradingDbContext> options) : base(options) { }

        public DbSet<ClosedTrade> ClosedTrades => Set<ClosedTrade>();
        public DbSet<TrackedTrader> Traders => Set<TrackedTrader>();
        public DbSet<CopyTradingAccountSettings> AccountSettings => Set<CopyTradingAccountSettings>();
        public DbSet<MasterTraderHistoryRecord> History => Set<MasterTraderHistoryRecord>();

        protected override void OnModelCreating(ModelBuilder b)
        {
            b.Ignore<ClosedTradeRow>();   // reine UI-Anzeige-Klasse

            b.Entity<ClosedTrade>(e =>
            {
                e.ToTable("mod_copytrading_closed_trades");
                e.HasKey(x => x.TradeId);
                e.Property(x => x.TradeId).ValueGeneratedNever();
                e.Property(x => x.TokenId).HasMaxLength(120);
                e.Property(x => x.MarketSlug).HasMaxLength(300);
                e.Property(x => x.MarketQuestion).HasMaxLength(1000);
                e.Property(x => x.Outcome).HasMaxLength(200);
                e.Property(x => x.Side).HasMaxLength(10);
                e.Property(x => x.ExitReason).HasMaxLength(200);
                e.Property(x => x.EntryPrice).HasPrecision(18, 6);
                e.Property(x => x.ExitPrice).HasPrecision(18, 6);
                e.Property(x => x.Size).HasPrecision(18, 6);
                e.Property(x => x.RealizedPnl).HasPrecision(18, 6);
                e.Property(x => x.PnlPercent).HasPrecision(18, 6);
                e.Property(x => x.TotalFees).HasPrecision(18, 6);
                e.Property(x => x.SignalId).HasMaxLength(40);   // Korrelation zum Entscheidungsjournal
                e.HasIndex(x => x.AccountId);
                e.HasIndex(x => x.TokenId);
                e.HasIndex(x => x.SourceTraderId);
            });

            b.Entity<TrackedTrader>(e =>
            {
                e.ToTable("mod_copytrading_traders");
                e.HasKey(x => x.Id);
                e.Property(x => x.Id).ValueGeneratedNever();
                e.Property(x => x.WalletAddress).HasMaxLength(128);
                e.Property(x => x.DisplayName).HasMaxLength(200);
                e.Property(x => x.Category).HasMaxLength(64);
                e.Property(x => x.Description).HasMaxLength(1000);
                e.Property(x => x.Reasoning).HasMaxLength(1000);
                e.Property(x => x.CopyPnl30d).HasPrecision(18, 6);
                e.Property(x => x.CopyProfitFactor).HasPrecision(18, 6);
                e.Property(x => x.CopyAvgPnlPerTrade).HasPrecision(18, 6);

                var comparer = new ValueComparer<HashSet<int>>(
                    (a, c) => (a == null && c == null) || (a != null && c != null && a.SetEquals(c)),
                    v => v.Aggregate(0, (h, i) => HashCode.Combine(h, i)),
                    v => new HashSet<int>(v));

                e.Property(x => x.AssignedAccountIds)
                    .HasConversion(
                        v => JsonSerializer.Serialize(v, (JsonSerializerOptions?)null),
                        v => string.IsNullOrEmpty(v) ? new HashSet<int>() : (JsonSerializer.Deserialize<HashSet<int>>(v, (JsonSerializerOptions?)null) ?? new HashSet<int>()))
                    .HasColumnType("text");
                e.Property(x => x.AssignedAccountIds).Metadata.SetValueComparer(comparer);
            });

            b.Entity<CopyTradingAccountSettings>(e =>
            {
                e.ToTable("mod_copytrading_account_settings");
                e.HasKey(x => x.AccountId);
                e.Property(x => x.AccountId).ValueGeneratedNever();
                e.Property(x => x.PerMarketLimit).HasPrecision(18, 6);
                e.Property(x => x.MaxPriceDifference).HasPrecision(18, 6);
                e.Property(x => x.MaxBuyPrice).HasPrecision(18, 6);
                e.Property(x => x.ProfitTarget).HasPrecision(18, 6);
                e.Property(x => x.PreRedeemLimit).HasPrecision(18, 6);
                e.Property(x => x.PerMasterLimit).HasPrecision(18, 6);
                e.Property(x => x.perMaxTime6h).HasPrecision(18, 6);
                e.Property(x => x.perMaxTime24h).HasPrecision(18, 6);
                e.Property(x => x.perMaxTime72h).HasPrecision(18, 6);
                e.Property(x => x.perMaxTimeNone).HasPrecision(18, 6);
                e.Property(x => x.SellFloorPct).HasPrecision(18, 6);
                e.Property(x => x.MaxSpreadPct).HasPrecision(18, 6);
                e.Property(x => x.MinSellRatioPct).HasPrecision(18, 6);
            });

            b.Entity<MasterTraderHistoryRecord>(e =>
            {
                e.ToTable("mod_copytrading_mt_history");
                e.HasKey(x => x.Id);
                e.Property(x => x.Id).HasMaxLength(64);
                e.Property(x => x.TokenId).HasMaxLength(120);
                e.Property(x => x.RealizedPnl).HasPrecision(18, 6);
                e.HasIndex(x => x.TraderId);
                e.HasIndex(x => x.ClosedAt);
            });
        }
    }
}
