using CommunityToolkit.Mvvm.ComponentModel;
using ClaudeDo.Data.Models;
using ClaudeDo.Ui.Localization;
using TaskStatus = ClaudeDo.Data.Models.TaskStatus;

namespace ClaudeDo.Ui.ViewModels.Islands;

public sealed partial class TaskRowViewModel : ViewModelBase
{
    public required string Id { get; init; }
    [ObservableProperty] private string _title = "";
    [ObservableProperty] private string _listName = "";
    [ObservableProperty] private bool _done;
    [ObservableProperty] private bool _isStarred;
    [ObservableProperty] private bool _isMyDay;
    [ObservableProperty] private bool _isSelected;
    [ObservableProperty] private TaskStatus _status;
    [ObservableProperty] private PlanningPhase _planningPhase;
    [ObservableProperty] private string? _branch;
    [ObservableProperty] private string? _diffStat;
    [ObservableProperty] private ClaudeDo.Data.Models.WorktreeState? _worktreeState;
    [ObservableProperty] private DateTime? _scheduledFor;
    [ObservableProperty] private int _diffAdditions;
    [ObservableProperty] private int _diffDeletions;
    [ObservableProperty] private bool _dropHintAbove;
    [ObservableProperty] private bool _dropHintBelow;
    [ObservableProperty] private string? _parentTaskId;
    [ObservableProperty] private string? _createdBy;
    [ObservableProperty] private string? _blockedByTaskId;
    [ObservableProperty] private bool _isExpanded = true;
    [ObservableProperty] private bool _hasPlanningChildren;
    [ObservableProperty] private bool _hasQueuedSubtasks;
    [ObservableProperty] private bool _showListChip = true;
    [ObservableProperty] private bool _parentFinalized;
    [ObservableProperty] private bool _parentInView = true;
    [ObservableProperty] private int _roadblockCount;
    [ObservableProperty] private bool _isRefining;

    public bool CanRefine => Status == TaskStatus.Idle && PlanningPhase == PlanningPhase.None && !IsRefining;

    public DateTime CreatedAt { get; init; }
    public string CreatedAtFormatted => CreatedAt == default ? "—" : Loc.T("vm.taskRow.createdPrefix", CreatedAt.ToString("MMM d"));

    public int StepsCount { get; init; }
    public int StepsCompleted { get; init; }

    public bool IsChild            => !string.IsNullOrEmpty(ParentTaskId);
    public bool IsAgentSuggested   => IsChild && !string.IsNullOrEmpty(CreatedBy) && CreatedBy == ParentTaskId;
    public bool IsPlanningParent => PlanningPhase != PlanningPhase.None
                                  || HasPlanningChildren;
    // A child only reads as a child while its parent shares the current view. When the parent is
    // absent (removed from My Day, or daily-prep placed a lone child there), the row renders as a
    // normal top-level task instead of an orphaned, indented Draft.
    public bool ShowAsChild      => IsChild && ParentInView;
    // A subtask is Draft until its planning parent is finalized, then Planned (queueable).
    public bool IsDraft          => ShowAsChild && Status == TaskStatus.Idle && !ParentFinalized;
    public bool IsPlanned        => ShowAsChild && Status == TaskStatus.Idle && ParentFinalized;

    public bool CanOpenPlanningSession   => Status == TaskStatus.Idle
                                          && PlanningPhase == PlanningPhase.None
                                          && !IsChild;
    public bool CanResumeOrDiscardPlanning => PlanningPhase == PlanningPhase.Active;

    public string? PlanningBadge => PlanningPhase switch
    {
        PlanningPhase.Active    => Loc.T("vm.planningBadge.active"),
        PlanningPhase.Finalized => Loc.T("vm.planningBadge.finalized"),
        _                       => null,
    };

    public bool IsPlanActive    => PlanningPhase == PlanningPhase.Active;
    public bool IsPlanFinalized => PlanningPhase == PlanningPhase.Finalized;

    public bool HasBranch   => !string.IsNullOrWhiteSpace(Branch);
    public bool HasDiff     => DiffAdditions > 0 || DiffDeletions > 0;
    public bool HasSteps    => StepsCount > 0;
    public bool IsOverdue   => ScheduledFor is { } d && d.Date < DateTime.Today && !Done;
    public bool IsRunning   => Status == TaskStatus.Running;
    public bool IsWaitingForReview => Status == TaskStatus.WaitingForReview;
    // Parked = set aside from review: Idle but still holding its Active worktree (vs a plain Idle task).
    public bool IsParked    => Status == TaskStatus.Idle && WorktreeState == ClaudeDo.Data.Models.WorktreeState.Active;
    public bool IsQueued    => Status == TaskStatus.Queued && string.IsNullOrEmpty(BlockedByTaskId);
    public bool IsWaiting   => Status == TaskStatus.Queued && !string.IsNullOrEmpty(BlockedByTaskId);
    public bool CanRemoveFromQueue => IsQueued || HasQueuedSubtasks;
    // "Send to queue" is the single queue entry. On a finalized planning parent it queues the
    // plan (children) via CanQueuePlan; an Active (not-yet-finalized) planning parent is hidden —
    // it must be finalized first.
    public bool CanSendToQueue => !IsRunning && !IsQueued && !IsWaitingForReview && !HasQueuedSubtasks
                                  && (!IsChild || ParentFinalized)
                                  && PlanningPhase != PlanningPhase.Active;
    // Parent-level "send plan to queue" — only once the plan is finalized (children Planned).
    // Drives the routing inside SendToQueue, not a separate menu entry.
    public bool CanQueuePlan => !IsChild && HasPlanningChildren
                                && PlanningPhase == PlanningPhase.Finalized
                                && !HasQueuedSubtasks;
    // User-triggered finalize for a planning parent whose session was closed before finalizing.
    public bool CanFinalizePlanning => PlanningPhase == PlanningPhase.Active && !IsChild;
    public bool HasSchedule => ScheduledFor.HasValue;
    // "Add to My Day" — shown on any task not already in My Day; a Done task has no place in
    // today's focus list. The mirror of "Remove from My Day" (gated on IsMyDay).
    public bool CanAddToMyDay => !IsMyDay && !Done;
    public bool HasRoadblock => RoadblockCount > 0;
    public string RoadblockTooltip => RoadblockCount == 1
        ? "1 roadblock reported during the run — see details"
        : $"{RoadblockCount} roadblocks reported during the run — see details";

    public string DiffAdditionsText => $"+{DiffAdditions}";
    public string DiffDeletionsText => $"−{DiffDeletions}";
    public string StepsText         => Loc.T("vm.taskRow.stepsText", StepsCompleted, StepsCount);

    public string StatusLabel => IsParked ? Loc.T("vm.taskStatus.parked") : Status switch
    {
        TaskStatus.Idle             => Loc.T("vm.taskStatus.idle"),
        TaskStatus.Queued           => Loc.T("vm.taskStatus.queued"),
        TaskStatus.Running          => Loc.T("vm.taskStatus.running"),
        TaskStatus.WaitingForReview    => Loc.T("vm.taskStatus.waitingForReview"),
        TaskStatus.WaitingForChildren  => Loc.T("vm.taskStatus.waitingForChildren"),
        TaskStatus.Done             => Loc.T("vm.taskStatus.done"),
        TaskStatus.Failed           => Loc.T("vm.taskStatus.failed"),
        TaskStatus.Cancelled        => Loc.T("vm.taskStatus.cancelled"),
        _                           => Status.ToString(),
    };

    public string StatusChipClass => (Status, IsBlocked: !string.IsNullOrEmpty(BlockedByTaskId)) switch
    {
        (TaskStatus.Running,            _) => "running",
        (TaskStatus.WaitingForReview,   _) => "review",
        (TaskStatus.WaitingForChildren, _) => "children",
        (TaskStatus.Failed,           _) => "error",
        (TaskStatus.Done,             _) => "done",
        (TaskStatus.Queued,        true) => "waiting",
        (TaskStatus.Queued,       false) => "queued",
        _                                => "idle",
    };

    partial void OnStatusChanged(TaskStatus value)
    {
        OnPropertyChanged(nameof(StatusChipClass));
        OnPropertyChanged(nameof(StatusLabel));
        OnPropertyChanged(nameof(IsRunning));
        OnPropertyChanged(nameof(IsWaitingForReview));
        OnPropertyChanged(nameof(IsParked));
        OnPropertyChanged(nameof(IsQueued));
        OnPropertyChanged(nameof(IsWaiting));
        OnPropertyChanged(nameof(IsDraft));
        OnPropertyChanged(nameof(IsPlanned));
        OnPropertyChanged(nameof(CanOpenPlanningSession));
        OnPropertyChanged(nameof(CanRemoveFromQueue));
        OnPropertyChanged(nameof(CanSendToQueue));
        OnPropertyChanged(nameof(CanRefine));
    }

    partial void OnParentTaskIdChanged(string? value)
    {
        OnPropertyChanged(nameof(IsChild));
        OnPropertyChanged(nameof(IsAgentSuggested));
        OnPropertyChanged(nameof(ShowAsChild));
        OnPropertyChanged(nameof(IsDraft));
        OnPropertyChanged(nameof(IsPlanned));
        OnPropertyChanged(nameof(CanSendToQueue));
        OnPropertyChanged(nameof(CanOpenPlanningSession));
    }

    partial void OnParentInViewChanged(bool value)
    {
        OnPropertyChanged(nameof(ShowAsChild));
        OnPropertyChanged(nameof(IsDraft));
        OnPropertyChanged(nameof(IsPlanned));
    }

    partial void OnCreatedByChanged(string? value) => OnPropertyChanged(nameof(IsAgentSuggested));

    partial void OnParentFinalizedChanged(bool value)
    {
        OnPropertyChanged(nameof(IsDraft));
        OnPropertyChanged(nameof(IsPlanned));
        OnPropertyChanged(nameof(CanSendToQueue));
    }

    partial void OnPlanningPhaseChanged(PlanningPhase value)
    {
        OnPropertyChanged(nameof(IsPlanningParent));
        OnPropertyChanged(nameof(PlanningBadge));
        OnPropertyChanged(nameof(IsPlanActive));
        OnPropertyChanged(nameof(IsPlanFinalized));
        OnPropertyChanged(nameof(CanOpenPlanningSession));
        OnPropertyChanged(nameof(CanResumeOrDiscardPlanning));
        OnPropertyChanged(nameof(CanQueuePlan));
        OnPropertyChanged(nameof(CanSendToQueue));
        OnPropertyChanged(nameof(CanFinalizePlanning));
        OnPropertyChanged(nameof(CanRefine));
    }

    partial void OnIsRefiningChanged(bool value) => OnPropertyChanged(nameof(CanRefine));

    partial void OnHasQueuedSubtasksChanged(bool value)
    {
        OnPropertyChanged(nameof(CanRemoveFromQueue));
        OnPropertyChanged(nameof(CanSendToQueue));
        OnPropertyChanged(nameof(CanQueuePlan));
    }

    partial void OnBlockedByTaskIdChanged(string? value)
    {
        OnPropertyChanged(nameof(IsQueued));
        OnPropertyChanged(nameof(IsWaiting));
        OnPropertyChanged(nameof(StatusChipClass));
    }

    partial void OnHasPlanningChildrenChanged(bool value)
    {
        OnPropertyChanged(nameof(IsPlanningParent));
        OnPropertyChanged(nameof(CanQueuePlan));
    }

    partial void OnBranchChanged(string? value)    => OnPropertyChanged(nameof(HasBranch));
    partial void OnWorktreeStateChanged(ClaudeDo.Data.Models.WorktreeState? value)
    {
        OnPropertyChanged(nameof(IsParked));
        OnPropertyChanged(nameof(StatusLabel));
    }
    partial void OnDoneChanged(bool value)
    {
        OnPropertyChanged(nameof(IsOverdue));
        OnPropertyChanged(nameof(CanAddToMyDay));
    }
    partial void OnIsMyDayChanged(bool value)      => OnPropertyChanged(nameof(CanAddToMyDay));
    partial void OnScheduledForChanged(DateTime? value)
    {
        OnPropertyChanged(nameof(IsOverdue));
        OnPropertyChanged(nameof(HasSchedule));
    }
    partial void OnDiffAdditionsChanged(int value) { OnPropertyChanged(nameof(HasDiff)); OnPropertyChanged(nameof(DiffAdditionsText)); }
    partial void OnDiffDeletionsChanged(int value) { OnPropertyChanged(nameof(HasDiff)); OnPropertyChanged(nameof(DiffDeletionsText)); }
    partial void OnRoadblockCountChanged(int value) { OnPropertyChanged(nameof(HasRoadblock)); OnPropertyChanged(nameof(RoadblockTooltip)); }

    public void RefreshLocalized()
    {
        OnPropertyChanged(nameof(StatusLabel));
        OnPropertyChanged(nameof(PlanningBadge));
        OnPropertyChanged(nameof(CreatedAtFormatted));
        OnPropertyChanged(nameof(StepsText));
    }

    public static TaskRowViewModel FromEntity(TaskEntity t)
    {
        var row = new TaskRowViewModel { Id = t.Id, CreatedAt = t.CreatedAt };
        row.UpdateFromEntity(t);
        return row;
    }

    public void UpdateFromEntity(TaskEntity t)
    {
        var (add, del) = ParseDiffStat(t.Worktree?.DiffStat);
        Title             = t.Title;
        ListName          = t.List?.Name ?? "";
        Done              = t.Status == TaskStatus.Done;
        IsStarred         = t.IsStarred;
        IsMyDay           = t.IsMyDay;
        Status            = t.Status;
        PlanningPhase     = t.PlanningPhase;
        Branch            = t.Worktree?.BranchName;
        DiffStat          = t.Worktree?.DiffStat;
        WorktreeState     = t.Worktree?.State;
        ScheduledFor      = t.ScheduledFor;
        DiffAdditions     = add;
        DiffDeletions     = del;
        ParentTaskId      = t.ParentTaskId;
        CreatedBy         = t.CreatedBy;
        BlockedByTaskId   = t.BlockedByTaskId;
        RoadblockCount    = t.RoadblockCount;
    }

    // Best-effort parse of diff stat strings like "+12 -3" or "12 additions, 3 deletions".
    private static (int add, int del) ParseDiffStat(string? s)
    {
        if (string.IsNullOrWhiteSpace(s)) return (0, 0);
        int add = 0, del = 0;
        var parts = s.Split(new[] { ' ', ',', '\t' }, StringSplitOptions.RemoveEmptyEntries);
        foreach (var p in parts)
        {
            if (p.Length > 1 && p[0] == '+' && int.TryParse(p.AsSpan(1), out var a)) add = a;
            else if (p.Length > 1 && (p[0] == '-' || p[0] == '\u2212') && int.TryParse(p.AsSpan(1), out var d)) del = d;
        }
        return (add, del);
    }
}
