using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using PolyTrader.Core.Configuration;

namespace PolyTrader.Modules.Supervisor.Persistence
{
    /// <summary>EF-Kontext des Supervisor-Moduls (gleiche MySQL-DB, Tabellen mit Präfix sup_).</summary>
    public class SupervisorDbContext : DbContext
    {
        public SupervisorDbContext(DbContextOptions<SupervisorDbContext> options) : base(options) { }

        public DbSet<SupervisorReport> Reports => Set<SupervisorReport>();
        public DbSet<Counterfactual.CounterfactualRecord> Counterfactuals => Set<Counterfactual.CounterfactualRecord>();

        protected override void OnModelCreating(ModelBuilder b)
        {
            b.Entity<SupervisorReport>(e =>
            {
                e.ToTable("sup_reports");
                e.HasKey(x => x.Id);
                e.Property(x => x.Id).ValueGeneratedOnAdd();
                e.Property(x => x.Profile).HasMaxLength(50);
                e.Property(x => x.Model).HasMaxLength(120);
                e.Property(x => x.Question).HasMaxLength(4000);
                e.Property(x => x.Answer).HasColumnType("text");
                e.Property(x => x.ToolCallsJson).HasColumnType("text");
                e.HasIndex(x => x.CreatedAt);
            });

            b.Entity<Counterfactual.CounterfactualRecord>(e =>
            {
                e.ToTable("sup_counterfactuals");
                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.Reason).HasMaxLength(50);
                e.Property(x => x.SignalPrice).HasPrecision(18, 6);
                e.Property(x => x.HypotheticalPnlPerShare).HasPrecision(18, 6);
                e.HasIndex(x => x.DecisionId).IsUnique();   // ein Ergebnis je Entscheidung
                e.HasIndex(x => x.CheckedAt);
                e.HasIndex(x => x.Reason);
            });
        }
    }

    /// <summary>
    /// Design-Time-Factory (fixe Server-Version → Migrations-Scaffolding OHNE DB-Verbindung).
    /// </summary>
    public class SupervisorDbContextFactory : IDesignTimeDbContextFactory<SupervisorDbContext>
    {
        public SupervisorDbContext CreateDbContext(string[] args)
        {
            var conn = Environment.GetEnvironmentVariable("POLYTRADER_MYSQL")
                ?? "Server=localhost;Port=3306;Database=polytrader;User ID=root;Password=;";
            var options = new DbContextOptionsBuilder<SupervisorDbContext>()
                .UseMySql(conn, DatabaseServerVersion.Value)
                .Options;
            return new SupervisorDbContext(options);
        }
    }

    /// <summary>Bericht-Ablage. Write fehlertolerant (Analyse darf nie an der Persistenz scheitern).</summary>
    public interface ISupervisorReportRepository
    {
        void Insert(SupervisorReport report);
        List<SupervisorReport> GetRecent(int limit);
    }

    /// <summary>Counterfactual-Ablage. Write fehlertolerant.</summary>
    public interface ISupervisorCounterfactualRepository
    {
        HashSet<long> ExistingDecisionIds(IEnumerable<long> decisionIds);
        void Insert(Counterfactual.CounterfactualRecord record);
        List<Counterfactual.CounterfactualRecord> GetRecent(int limit);
    }

    public class EfSupervisorCounterfactualRepository : ISupervisorCounterfactualRepository
    {
        private readonly IDbContextFactory<SupervisorDbContext> _factory;
        public EfSupervisorCounterfactualRepository(IDbContextFactory<SupervisorDbContext> factory) => _factory = factory;

        public HashSet<long> ExistingDecisionIds(IEnumerable<long> decisionIds)
        {
            var ids = decisionIds.ToList();
            using var ctx = _factory.CreateDbContext();
            return ctx.Counterfactuals.AsNoTracking()
                .Where(c => ids.Contains(c.DecisionId))
                .Select(c => c.DecisionId)
                .ToHashSet();
        }

        public void Insert(Counterfactual.CounterfactualRecord record)
        {
            try
            {
                using var ctx = _factory.CreateDbContext();
                ctx.Counterfactuals.Add(record);
                ctx.SaveChanges();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[Counterfactuals] Write fehlgeschlagen (ignoriert): {ex.Message}");
            }
        }

        public List<Counterfactual.CounterfactualRecord> GetRecent(int limit)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Counterfactuals.AsNoTracking().OrderByDescending(c => c.CheckedAt).Take(limit).ToList();
        }
    }

    public class EfSupervisorReportRepository : ISupervisorReportRepository
    {
        private readonly IDbContextFactory<SupervisorDbContext> _factory;
        public EfSupervisorReportRepository(IDbContextFactory<SupervisorDbContext> factory) => _factory = factory;

        public void Insert(SupervisorReport report)
        {
            try
            {
                using var ctx = _factory.CreateDbContext();
                ctx.Reports.Add(report);
                ctx.SaveChanges();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[SupervisorReports] Write fehlgeschlagen (ignoriert): {ex.Message}");
            }
        }

        public List<SupervisorReport> GetRecent(int limit)
        {
            using var ctx = _factory.CreateDbContext();
            return ctx.Reports.AsNoTracking().OrderByDescending(r => r.CreatedAt).Take(limit).ToList();
        }
    }
}
