using ClaudeDo.Data.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;

namespace ClaudeDo.Data.Configuration;

public class TaskEntityConfiguration : IEntityTypeConfiguration<TaskEntity>
{
    private static string StatusToString(TaskStatus v)
        => v == TaskStatus.Manual ? "manual"
         : v == TaskStatus.Queued ? "queued"
         : v == TaskStatus.Running ? "running"
         : v == TaskStatus.Done ? "done"
         : v == TaskStatus.Failed ? "failed"
         : throw new ArgumentOutOfRangeException(nameof(v));

    private static TaskStatus StatusFromString(string v)
        => v == "manual" ? TaskStatus.Manual
         : v == "queued" ? TaskStatus.Queued
         : v == "running" ? TaskStatus.Running
         : v == "done" ? TaskStatus.Done
         : v == "failed" ? TaskStatus.Failed
         : throw new ArgumentOutOfRangeException(nameof(v));

    private static readonly ValueConverter<TaskStatus, string> StatusConverter =
        new(v => StatusToString(v), v => StatusFromString(v));

    public void Configure(EntityTypeBuilder<TaskEntity> builder)
    {
        builder.ToTable("tasks");

        builder.HasKey(t => t.Id);
        builder.Property(t => t.Id).HasColumnName("id");
        builder.Property(t => t.ListId).HasColumnName("list_id").IsRequired();
        builder.Property(t => t.Title).HasColumnName("title").IsRequired();
        builder.Property(t => t.Description).HasColumnName("description");
        builder.Property(t => t.Status).HasColumnName("status").IsRequired()
            .HasConversion(StatusConverter);
        builder.Property(t => t.ScheduledFor).HasColumnName("scheduled_for");
        builder.Property(t => t.Result).HasColumnName("result");
        builder.Property(t => t.LogPath).HasColumnName("log_path");
        builder.Property(t => t.CreatedAt).HasColumnName("created_at").IsRequired();
        builder.Property(t => t.StartedAt).HasColumnName("started_at");
        builder.Property(t => t.FinishedAt).HasColumnName("finished_at");
        builder.Property(t => t.CommitType).HasColumnName("commit_type").IsRequired().HasDefaultValue("chore");
        builder.Property(t => t.Model).HasColumnName("model");
        builder.Property(t => t.SystemPrompt).HasColumnName("system_prompt");
        builder.Property(t => t.AgentPath).HasColumnName("agent_path");
        builder.Property(t => t.IsStarred).HasColumnName("is_starred").HasDefaultValue(false);
        builder.Property(t => t.IsMyDay).HasColumnName("is_my_day").HasDefaultValue(false);
        builder.Property(t => t.Notes).HasColumnName("notes");
        builder.Property(t => t.SortOrder).HasColumnName("sort_order").IsRequired().HasDefaultValue(0);

        builder.HasOne(t => t.List)
            .WithMany(l => l.Tasks)
            .HasForeignKey(t => t.ListId)
            .OnDelete(DeleteBehavior.Cascade);

        builder.HasOne(t => t.Worktree)
            .WithOne(w => w.Task)
            .HasForeignKey<WorktreeEntity>(w => w.TaskId);

        builder.HasMany(t => t.Tags)
            .WithMany(tag => tag.Tasks)
            .UsingEntity("task_tags",
                l => l.HasOne(typeof(TagEntity)).WithMany().HasForeignKey("tag_id").OnDelete(DeleteBehavior.Cascade),
                r => r.HasOne(typeof(TaskEntity)).WithMany().HasForeignKey("task_id").OnDelete(DeleteBehavior.Cascade),
                j =>
                {
                    j.HasKey("task_id", "tag_id");
                    j.ToTable("task_tags");
                });

        builder.HasIndex(t => t.ListId).HasDatabaseName("idx_tasks_list_id");
        builder.HasIndex(t => t.Status).HasDatabaseName("idx_tasks_status");
        builder.HasIndex(t => new { t.ListId, t.SortOrder }).HasDatabaseName("idx_tasks_list_sort");
    }
}
