using Microsoft.EntityFrameworkCore;
using PolyTrader.Core.Security;
using PolyTraderSharp.Models;

namespace PolyTrader.Core.Persistence.Ef
{
    /// <summary>
    /// EF-Core-Kontext für die Core-Entitäten (eigene Trading-Accounts, Positionen,
    /// Markt-Cache, generischer Trade-Log). Modul-Entitäten liegen im
    /// CopyTradingDbContext des Moduls (gleiche MySQL-DB, andere Tabellen).
    /// </summary>
    public class CoreDbContext : DbContext
    {
        public CoreDbContext(DbContextOptions<CoreDbContext> options) : base(options) { }

        public DbSet<AccountState> Accounts => Set<AccountState>();
        public DbSet<Position> Positions => Set<Position>();
        public DbSet<MarketData> Markets => Set<MarketData>();
        public DbSet<TradeRecord> TradeLog => Set<TradeRecord>();
        public DbSet<DecisionRecord> DecisionJournal => Set<DecisionRecord>();
        public DbSet<OrderEventRecord> OrderEvents => Set<OrderEventRecord>();

        protected override void OnModelCreating(ModelBuilder b)
        {
            b.Entity<AccountState>(e =>
            {
                e.ToTable("core_accounts");
                e.HasKey(x => x.AccountId);
                e.Property(x => x.AccountId).ValueGeneratedNever();
                e.Ignore(x => x.OpenPositions);            // Runtime-Only (In-Memory Hot-Path)
                e.Property(x => x.Name).HasMaxLength(200);
                e.Property(x => x.WalletAddress).HasMaxLength(128);
                e.Property(x => x.ApiKey).HasMaxLength(256);
                // F1: sensible Secrets at-rest verschlüsselt (AES-256-GCM, Master-Key außerhalb der DB).
                // Spalten verbreitert (Ciphertext+Base64 länger als Klartext). Alt-Klartext bleibt lesbar
                // und wird beim nächsten Speichern verschlüsselt (selbstheilend).
                e.Property(x => x.ApiSecret).HasMaxLength(512).HasConversion(new EncryptedStringConverter());
                e.Property(x => x.ApiPassphrase).HasMaxLength(512).HasConversion(new EncryptedStringConverter());
                e.Property(x => x.PrivateKey).HasMaxLength(512).HasConversion(new EncryptedStringConverter());
                e.Property(x => x.PayoutAddress).HasMaxLength(128);
                e.Property(x => x.TotalBalance).HasPrecision(18, 6);
                e.Property(x => x.AvailableBalance).HasPrecision(18, 6);
                e.Property(x => x.PayoutLimitUsd).HasPrecision(18, 6);
            });

            b.Entity<Position>(e =>
            {
                e.ToTable("core_positions");
                e.HasKey(x => new { x.AccountId, x.IsDemo, x.TokenId });
                e.Ignore(x => x.ExitPending);   // Runtime-only (SELL-Eskalationsleiter)
                e.Property(x => x.TokenId).HasMaxLength(120);
                e.Property(x => x.MarketSlug).HasMaxLength(300);
                e.Property(x => x.ConditionId).HasMaxLength(120);
                e.Property(x => x.SourceTraderName).HasMaxLength(200);
                e.Property(x => x.SourceTraderAddress).HasMaxLength(128);
                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.EntryPrice).HasPrecision(18, 6);
                e.Property(x => x.Size).HasPrecision(18, 6);
                e.Property(x => x.AmountUsd).HasPrecision(18, 6);
                e.Property(x => x.CurrentPrice).HasPrecision(18, 6);
                e.Property(x => x.CurrentValueUsd).HasPrecision(18, 6);
            });

            b.Entity<MarketData>(e =>
            {
                e.ToTable("core_markets");
                e.HasKey(x => x.Id);
                e.Property(x => x.Id).HasMaxLength(120);
                e.Property(x => x.ConditionId).HasMaxLength(120);
                e.Property(x => x.Slug).HasMaxLength(300);
                e.Property(x => x.Category).HasMaxLength(200);
                e.Property(x => x.Question).HasMaxLength(1000);
                e.Property(x => x.ClobTokenIds).HasColumnType("text");
                e.Property(x => x.Outcomes).HasColumnType("text");
            });

            b.Entity<TradeRecord>(e =>
            {
                e.ToTable("core_trade_log");
                e.HasKey(x => x.Id);
                e.Property(x => x.Id).HasMaxLength(64);
                e.Property(x => x.ModuleName).HasMaxLength(64);
                e.Property(x => x.TokenId).HasMaxLength(120);
                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.HasIndex(x => x.ClosedAt);
                e.HasIndex(x => x.ModuleName);
                e.HasIndex(x => x.AccountId);
                e.Property(x => x.SignalId).HasMaxLength(40);   // Korrelation zum Entscheidungsjournal
            });

            // Entscheidungsjournal (S-0, Supervisor-Konzept): jede Handelsentscheidung strukturiert.
            b.Entity<DecisionRecord>(e =>
            {
                e.ToTable("core_decision_journal");
                e.HasKey(x => x.Id);
                e.Property(x => x.Id).ValueGeneratedOnAdd();
                e.Property(x => x.SignalId).HasMaxLength(40);
                e.Property(x => x.ModuleName).HasMaxLength(64);
                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.Side).HasMaxLength(10);
                e.Property(x => x.SignalPrice).HasPrecision(18, 6);
                // Enums als String: lesbar in der DB, gefahrlos erweiterbar.
                e.Property(x => x.Decision).HasConversion<string>().HasMaxLength(20);
                e.Property(x => x.Reason).HasConversion<string>().HasMaxLength(50);
                e.Property(x => x.ContextJson).HasMaxLength(2000);
                e.Property(x => x.Message).HasMaxLength(2000);
                e.HasIndex(x => x.Timestamp);
                e.HasIndex(x => x.SignalId);
                e.HasIndex(x => new { x.AccountId, x.TokenId });
                e.HasIndex(x => x.Reason);
            });

            // Order-Lifecycle-Events (S-0): Platzierungen/Antworten/Cancels/Leiter-Stufen als Daten.
            b.Entity<OrderEventRecord>(e =>
            {
                e.ToTable("core_order_events");
                e.HasKey(x => x.Id);
                e.Property(x => x.Id).ValueGeneratedOnAdd();
                e.Property(x => x.SignalId).HasMaxLength(40);
                e.Property(x => x.ModuleName).HasMaxLength(64);
                e.Property(x => x.TokenId).HasMaxLength(120);
                e.Property(x => x.EventType).HasConversion<string>().HasMaxLength(30);
                e.Property(x => x.Side).HasMaxLength(10);
                e.Property(x => x.Price).HasPrecision(18, 6);
                e.Property(x => x.AmountUsd).HasPrecision(18, 6);
                e.Property(x => x.OrderType).HasMaxLength(10);
                e.Property(x => x.Response).HasMaxLength(1000);
                e.Property(x => x.DetailsJson).HasMaxLength(2000);
                e.HasIndex(x => x.Timestamp);
                e.HasIndex(x => x.SignalId);
                e.HasIndex(x => new { x.AccountId, x.TokenId });
            });
        }
    }
}
