using ClaudeDo.Data.Models;
using ClaudeDo.Data.Seeding;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;

namespace ClaudeDo.Data;

public class ClaudeDoDbContext : DbContext
{
    public ClaudeDoDbContext(DbContextOptions<ClaudeDoDbContext> options) : base(options) { }

    public DbSet<TaskEntity> Tasks => Set<TaskEntity>();
    public DbSet<ListEntity> Lists => Set<ListEntity>();
    public DbSet<TagEntity> Tags => Set<TagEntity>();
    public DbSet<ListConfigEntity> ListConfigs => Set<ListConfigEntity>();
    public DbSet<WorktreeEntity> Worktrees => Set<WorktreeEntity>();
    public DbSet<TaskRunEntity> TaskRuns => Set<TaskRunEntity>();
    public DbSet<SubtaskEntity> Subtasks => Set<SubtaskEntity>();
    public DbSet<AppSettingsEntity> AppSettings => Set<AppSettingsEntity>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfigurationsFromAssembly(typeof(ClaudeDoDbContext).Assembly);
    }

    /// <summary>
    /// Applies EF Core migrations and sets WAL mode. Safe for both fresh and existing databases.
    /// Existing databases (created by the old schema.sql) have their tables but no
    /// __EFMigrationsHistory — this method detects that case and baselines the initial
    /// migration so EF skips re-creating tables that already exist.
    /// </summary>
    public static void MigrateAndConfigure(ClaudeDoDbContext db)
    {
        var conn = db.Database.GetDbConnection();
        try
        {
            conn.Open();

            // Set WAL FIRST, before migrations — prevents write-lock contention
            // when UI and Worker start simultaneously.
            using (var walCmd = conn.CreateCommand())
            {
                walCmd.CommandText = "PRAGMA journal_mode=wal;";
                walCmd.ExecuteNonQuery();
            }

            // If the 'lists' table exists but __EFMigrationsHistory does not,
            // this is a pre-EF database. Baseline the InitialCreate migration.
            using (var cmd = conn.CreateCommand())
            {
                cmd.CommandText = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='lists'";
                var hasLists = Convert.ToInt64(cmd.ExecuteScalar()) > 0;

                cmd.CommandText = "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='__EFMigrationsHistory'";
                var hasHistory = Convert.ToInt64(cmd.ExecuteScalar()) > 0;

                if (hasLists && !hasHistory)
                {
                    cmd.CommandText = """
                        CREATE TABLE "__EFMigrationsHistory" (
                            "MigrationId" TEXT NOT NULL CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY,
                            "ProductVersion" TEXT NOT NULL
                        );
                        INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
                        VALUES ('20260416064948_InitialCreate', '8.0.11');
                        """;
                    cmd.ExecuteNonQuery();
                }
            }
        }
        finally
        {
            conn.Close();
        }

        db.Database.Migrate();
        DefaultListsSeeder.SeedAsync(db).GetAwaiter().GetResult();
    }
}
