/**
 * GetWorkspaceStatusOperation - Orchestrates workspace status queries.
 *
 * Runs two steps:
 * 1. Dispatch workspace:resolve to validate workspacePath
 * 2. "get" hook — each handler contributes a piece of the status
 *
 * No provider dependencies - hook handlers do the actual work.
 * No domain events - this is a query operation.
 */

import type { Intent } from "./lib/types";
import type { Operation, OperationContext, HookContext } from "./lib/operation";
import type { WorkspaceStatus } from "../shared/api/types";
import type { AggregatedAgentStatus } from "../shared/ipc";
import { INTENT_RESOLVE_WORKSPACE, type ResolveWorkspaceIntent } from "./resolve-workspace";
import { INTENT_GET_PROJECT_BASES, type GetProjectBasesIntent } from "./get-project-bases";

// =============================================================================
// Intent Types
// =============================================================================

export interface GetWorkspaceStatusPayload {
  readonly workspacePath: string;
  /**
   * If true, fetch remotes (via project:get-bases with refresh+wait) before
   * reading status. Best-effort: fetch failures are swallowed and the status
   * is read against possibly-stale local refs.
   */
  readonly refresh?: boolean;
}

export interface GetWorkspaceStatusIntent extends Intent<WorkspaceStatus> {
  readonly type: "workspace:get-status";
  readonly payload: GetWorkspaceStatusPayload;
}

export const INTENT_GET_WORKSPACE_STATUS = "workspace:get-status" as const;

// =============================================================================
// Hook Types
// =============================================================================

export const GET_WORKSPACE_STATUS_OPERATION_ID = "get-workspace-status";

/**
 * Input context for "get" handlers — built from resolve results.
 */
export interface GetStatusHookInput extends HookContext {
  readonly workspacePath: string;
}

/**
 * Per-handler result contract for the "get" hook point.
 * Each handler returns its contribution — the operation merges them.
 */
export interface GetStatusHookResult {
  readonly isDirty?: boolean;
  readonly unmergedCommits?: number;
  readonly agentStatus?: AggregatedAgentStatus;
}

// =============================================================================
// Operation
// =============================================================================

export class GetWorkspaceStatusOperation implements Operation<
  GetWorkspaceStatusIntent,
  WorkspaceStatus
> {
  readonly id = GET_WORKSPACE_STATUS_OPERATION_ID;

  async execute(ctx: OperationContext<GetWorkspaceStatusIntent>): Promise<WorkspaceStatus> {
    const { payload } = ctx.intent;

    // 1. Dispatch shared workspace resolution
    const { projectPath } = await ctx.dispatch({
      type: INTENT_RESOLVE_WORKSPACE,
      payload: { workspacePath: payload.workspacePath },
    } as ResolveWorkspaceIntent);

    // 2. Optional refresh — fetch remotes so unmerged-commit counts reflect
    // server-merged branches. Best-effort; errors are swallowed.
    if (payload.refresh) {
      try {
        await ctx.dispatch({
          type: INTENT_GET_PROJECT_BASES,
          payload: { projectPath, refresh: true, wait: true },
        } as GetProjectBasesIntent);
      } catch {
        // Fall through to status read with possibly-stale refs.
      }
    }

    // 3. get — each handler contributes its piece
    const getCtx: GetStatusHookInput = {
      intent: ctx.intent,
      workspacePath: payload.workspacePath,
    };
    const { results, errors } = await ctx.hooks.collect<GetStatusHookResult>("get", getCtx);
    if (errors.length > 0) {
      throw new AggregateError(errors, "get-workspace-status get hooks failed");
    }

    // Merge results — isDirty uses OR, unmergedCommits uses max
    let isDirty = false;
    let unmergedCommits = 0;
    let agentStatus: AggregatedAgentStatus | undefined;

    for (const result of results) {
      if (result.isDirty) isDirty = true;
      if (result.unmergedCommits !== undefined && result.unmergedCommits > unmergedCommits) {
        unmergedCommits = result.unmergedCommits;
      }
      if (result.agentStatus !== undefined) agentStatus = result.agentStatus;
    }

    const finalAgentStatus = agentStatus ?? {
      status: "none" as const,
      counts: { idle: 0, busy: 0 },
    };

    return {
      isDirty,
      unmergedCommits,
      agent:
        finalAgentStatus.status === "none"
          ? { type: "none" }
          : {
              type: finalAgentStatus.status,
              counts: {
                idle: finalAgentStatus.counts.idle,
                busy: finalAgentStatus.counts.busy,
                total: finalAgentStatus.counts.idle + finalAgentStatus.counts.busy,
              },
            },
    };
  }
}
