namespace ClaudeDo.Data.Models;

public enum TaskStatus
{
    Idle,
    Queued,
    Running,
    WaitingForReview,
    WaitingForChildren,
    Done,
    Failed,
    Cancelled,
}

public enum PlanningPhase
{
    None,
    Active,
    Finalized,
}

public sealed class TaskEntity
{
    public required string Id { get; init; }
    // Global, monotonically increasing, never-reused display/lookup handle shown as `#123`.
    // Allocated by TaskNumberAllocator from AppSettingsEntity.NextTaskNumber -- never MAX(number)+1,
    // which would reissue a deleted task's number. The GUID Id stays the real identity everywhere else.
    public int Number { get; set; }
    public required string ListId { get; init; }
    public required string Title { get; set; }
    public string? Description { get; set; }
    public TaskStatus Status { get; set; } = TaskStatus.Idle;
    public PlanningPhase PlanningPhase { get; set; } = PlanningPhase.None;
    public string? BlockedByTaskId { get; set; }

    // A user/MCP-declared predecessor, distinct from BlockedByTaskId (the planning chain's own
    // internal link): the picker also skips a Queued task while this is set and the referenced
    // task's Status isn't Done. Unlike the chain, a Failed/Cancelled dependency does NOT cascade
    // or auto-resolve -- the dependent just stays blocked and reports why (see TaskStateService.
    // SetDependsOnAsync and QueuePicker).
    public string? DependsOnTaskId { get; set; }
    public DateTime? ScheduledFor { get; set; }
    public string? Result { get; set; }
    public string? ReviewFeedback { get; set; }
    public int RoadblockCount { get; set; }
    // Denormalized from the failing run, same pattern as RoadblockCount, so get_task/
    // batch_get_tasks can report why a Failed task stopped without a second query.
    // Null on a non-Failed task, or on a Failed task predating this field ("unknown").
    public string? FailureReason { get; set; }
    public int? FailureTurnsUsed { get; set; }
    public int? FailureMaxTurns { get; set; }
    // Set once QueueService's UsageLimitAutoContinueCoordinator fires ContinueTask for a
    // FailureReason=="usage_limit" task. Guards against firing it a second time for the same
    // task — never reset automatically, so auto-continue never loops on a repeat limit hit.
    public DateTime? UsageLimitAutoContinuedAt { get; set; }
    public string? LogPath { get; set; }
    public required DateTime CreatedAt { get; init; }
    public DateTime? StartedAt { get; set; }
    public DateTime? FinishedAt { get; set; }
    public string CommitType { get; set; } = CommitTypeRegistry.DefaultType;
    public string? Model { get; set; }
    public string? SystemPrompt { get; set; }
    public string? AgentPath { get; set; }
    public int? MaxTurns { get; set; }
    // Null = inherit the list's config, then AppSettingsEntity.DefaultPermissionMode.
    // One of PermissionModeRegistry.Modes.
    public string? PermissionMode { get; set; }
    public bool IsStarred { get; set; }
    public bool IsMyDay { get; set; }
    // Manual = a reminder only the user can do. Automation skips it (queue picker, daily prep,
    // list handler) and the Claude affordances are hidden; a hand-driven ConPTY session is still
    // allowed. New tasks in a manual list default to true.
    public bool IsManual { get; set; }
    public string? Notes { get; set; }
    public int SortOrder { get; set; }
    public string? SessionSkills { get; set; }

    // Verknüpftes Ticket im externen Ticketsystem, Format "<provider>:<id>" (aktuell immer
    // "bandel:<ticketId>"). Gesetzt vom Ticket-Import, sonst null. Der Provider-Präfix existiert,
    // damit ein zweites Ticketsystem später keine Datenmigration braucht.
    public string? TicketRef { get; set; }

    // Review range for a worktree-less task hosting an interactive "list handler" run
    // (Mission Control's "Let Claude handle it"): the handler commits its own changes
    // straight to the list's working dir, so there is no per-task worktree to diff. These
    // capture the repo's HEAD at session start / submit-for-review instead, so the normal
    // diff/get_task_diff paths can show `HandlerBaseCommit..HandlerHeadCommit` over the
    // list's working dir exactly like a merged task's commit-range diff.
    public string? HandlerBaseCommit { get; set; }
    public string? HandlerHeadCommit { get; set; }

    // The claude session id an embedded ConPTY interactive task session is (or was last)
    // running under -- generated up front and persisted before launch so a closed/aborted
    // session can be resumed even if the process never got past startup. Cleared implicitly
    // whenever the task's worktree is recreated (a fresh worktree has nothing to resume into).
    public string? InteractiveSessionId { get; set; }

    public string? ParentTaskId { get; set; }
    public string? PlanningSessionId { get; set; }
    public string? PlanningSessionToken { get; set; }
    public DateTime? PlanningFinalizedAt { get; set; }

    public string? CreatedBy { get; set; }

    // Navigation properties
    public ListEntity List { get; set; } = null!;
    public WorktreeEntity? Worktree { get; set; }
    public ICollection<TaskRunEntity> Runs { get; set; } = new List<TaskRunEntity>();
    public ICollection<SubtaskEntity> Subtasks { get; set; } = new List<SubtaskEntity>();

    public TaskEntity? Parent { get; set; }
    public ICollection<TaskEntity> Children { get; set; } = new List<TaskEntity>();
}
