using ClaudeDo.Data.Models;
using ClaudeDo.Worker.Prime;
using ClaudeDo.Worker.Refine;
using Microsoft.AspNetCore.SignalR;

namespace ClaudeDo.Worker.Hub;

public sealed class HubBroadcaster : IPrimeBroadcaster, IRefineBroadcaster
{
    private readonly IHubContext<WorkerHub> _hub;

    public HubBroadcaster(IHubContext<WorkerHub> hub) => _hub = hub;

    public Task TaskStarted(string slot, string taskId, DateTime startedAt) =>
        _hub.Clients.All.SendAsync("TaskStarted", slot, taskId, startedAt);

    public Task TaskFinished(string slot, string taskId, string status, DateTime finishedAt) =>
        _hub.Clients.All.SendAsync("TaskFinished", slot, taskId, status, finishedAt);

    public Task TaskMessage(string taskId, string ndjsonLine) =>
        _hub.Clients.All.SendAsync("TaskMessage", taskId, ndjsonLine);

    public Task WorktreeUpdated(string taskId) =>
        _hub.Clients.All.SendAsync("WorktreeUpdated", taskId);

    public Task TaskUpdated(string taskId) =>
        _hub.Clients.All.SendAsync("TaskUpdated", taskId);

    public Task TaskQuestionAsked(string taskId, string questionId, string question) =>
        _hub.Clients.All.SendAsync("TaskQuestionAsked", taskId, questionId, question);

    public Task TaskQuestionResolved(string taskId, string questionId) =>
        _hub.Clients.All.SendAsync("TaskQuestionResolved", taskId, questionId);

    // A running list-handler session called handoff_list_handler at the end of Phase 2 -- the UI
    // opens a second ConPTY tile for the same handler task id to carry out Phases 3-5.
    public Task HandoffRequested(string taskId, IReadOnlyList<string> survivingTaskIds, string nextPhase) =>
        _hub.Clients.All.SendAsync("HandoffRequested", taskId, survivingTaskIds, nextPhase);

    /// <summary>An agent wrote a note through MCP — the open notes editor reloads.</summary>
    public Task NotesUpdated() =>
        _hub.Clients.All.SendAsync("NotesUpdated");

    public Task ListUpdated(string listId) =>
        _hub.Clients.All.SendAsync("ListUpdated", listId);

    public Task UsageUpdated(UsageSnapshotDto snapshot) =>
        _hub.Clients.All.SendAsync("UsageUpdated", snapshot);

    public Task WorkerLog(string message, WorkerLogLevel level, DateTime timestampUtc) =>
        _hub.Clients.All.SendAsync("WorkerLog", message, level, timestampUtc);

    // Generic progress channel for long-running worker operations (merge phases, worktree
    // cleanup, startup recovery, planning integration, ...). opKey is the TaskId for a
    // task-bound operation, otherwise a stable string ("worktree-cleanup", "startup-recovery",
    // "planning-integration:<taskId>"). current/total is shown as text by the UI, never a
    // progress bar -- most operations have no meaningful total.
    public Task OperationProgress(string opKey, string phase, int current, int total) =>
        _hub.Clients.All.SendAsync("OperationProgress", opKey, phase, current, total);

    public Task PlanningMergeStarted(string planningTaskId, string targetBranch) =>
        _hub.Clients.All.SendAsync("PlanningMergeStarted", planningTaskId, targetBranch);

    public Task PlanningSubtaskMerged(string planningTaskId, string subtaskId) =>
        _hub.Clients.All.SendAsync("PlanningSubtaskMerged", planningTaskId, subtaskId);

    public Task PlanningMergeConflict(
        string planningTaskId, string subtaskId, IReadOnlyList<string> files, bool externallyDriven) =>
        _hub.Clients.All.SendAsync("PlanningMergeConflict", planningTaskId, subtaskId, files, externallyDriven);

    public Task PlanningMergeAborted(string planningTaskId, string? reason) =>
        _hub.Clients.All.SendAsync("PlanningMergeAborted", planningTaskId, reason);

    public Task PlanningCompleted(string planningTaskId) =>
        _hub.Clients.All.SendAsync("PlanningCompleted", planningTaskId);

    public Task PrimeFired(Guid scheduleId, bool success, string message, DateTimeOffset firedAt) =>
        _hub.Clients.All.SendAsync("PrimeFired", scheduleId, success, message, firedAt);

    Task IPrimeBroadcaster.PrimeFiredAsync(Guid scheduleId, bool success, string message, DateTimeOffset firedAt) =>
        PrimeFired(scheduleId, success, message, firedAt);

    public Task PrepStarted() => _hub.Clients.All.SendAsync("PrepStarted");
    public Task PrepLine(string line) => _hub.Clients.All.SendAsync("PrepLine", line);
    public Task PrepFinished(bool success) => _hub.Clients.All.SendAsync("PrepFinished", success);

    Task IPrimeBroadcaster.PrepStartedAsync() => PrepStarted();
    Task IPrimeBroadcaster.PrepLineAsync(string line) => PrepLine(line);
    Task IPrimeBroadcaster.PrepFinishedAsync(bool success) => PrepFinished(success);

    public Task RefineStarted(string taskId) => _hub.Clients.All.SendAsync("RefineStarted", taskId);
    public Task RefineFinished(string taskId, bool success, string? error) =>
        _hub.Clients.All.SendAsync("RefineFinished", taskId, success, error);

    Task IRefineBroadcaster.RefineStartedAsync(string taskId) => RefineStarted(taskId);
    Task IRefineBroadcaster.RefineFinishedAsync(string taskId, bool success, string? error) =>
        RefineFinished(taskId, success, error);
}
