/**
 * CursorHostAdapter — Cursor-specific AgentHostAdapter (WP-04).
 * Compat wrap over CursorSdkAdapter / AgentSdkAdapter; production Active path unchanged.
 */

import type { AgentSdkAdapter } from "../../../registry/AgentSdkAdapter.ts";
import type { RuntimeEvent } from "../../../types/state.ts";
import type { AgentHostAdapter } from "../../contracts/AgentHostAdapter.ts";
import type { HostDescriptor } from "../../contracts/HostDescriptor.ts";
import type { HostEventEnvelope } from "../../contracts/HostEvent.ts";
import type { HostFailure } from "../../contracts/HostFailure.ts";
import type { HostRunRef, StartRunInput } from "../../contracts/HostRun.ts";
import type {
  HostSessionRef,
  HostSessionState,
  PrepareSessionInput,
  PreparedHostSession,
} from "../../contracts/HostSession.ts";
import { normalizeHostCapabilities } from "../../contracts/HostCapabilities.ts";
import {
  LegacySdkHostAdapter,
  type LegacySdkHostAdapterOptions,
} from "../LegacySdkHostAdapter.ts";
import { mapCursorRuntimeEventToHostEnvelope } from "./CursorHostEventMapper.ts";
import { classifyCursorHostFailure } from "./CursorHostFailureClassifier.ts";

export const CURSOR_HOST_CAPABILITIES = normalizeHostCapabilities({
  level: "H2",
  persistentSession: true,
  resumableSession: true,
  structuredEvents: true,
  cancellableRun: true,
  inspectableSession: true,
  workspaceBinding: true,
  concurrentWorkers: false,
  extensions: {
    transport: "cursor-sdk",
    switchboard_mode: "off",
    wraps: "CursorSdkAdapter",
  },
});

export interface CursorHostAdapterOptions extends LegacySdkHostAdapterOptions {
  /** Defaults to host-cursor. */
  hostId?: string;
}

/**
 * Formal Cursor host surface. Internally delegates session/run lifecycle to
 * LegacySdkHostAdapter (compat wrap), then applies Cursor event/failure mappers.
 */
export class CursorHostAdapter implements AgentHostAdapter {
  readonly hostId: string;
  readonly #inner: LegacySdkHostAdapter;
  readonly #displayName: string;
  readonly #enabled: boolean;

  constructor(sdk: AgentSdkAdapter, opts: CursorHostAdapterOptions = {}) {
    this.hostId = opts.hostId?.trim() || "host-cursor";
    this.#displayName = opts.displayName?.trim() || "Cursor Host";
    this.#enabled = opts.enabled !== false;
    this.#inner = new LegacySdkHostAdapter(sdk, {
      ...opts,
      hostId: this.hostId,
      displayName: this.#displayName,
      enabled: this.#enabled,
    });
  }

  /** Compat: expose underlying AgentSdkAdapter (typically CursorSdkAdapter). */
  get underlyingSdkAdapter(): AgentSdkAdapter {
    return this.#inner.underlyingSdkAdapter;
  }

  /** Compat: expose legacy wrap for migration diagnostics. */
  get legacyWrap(): LegacySdkHostAdapter {
    return this.#inner;
  }

  async describe(): Promise<HostDescriptor> {
    return {
      hostId: this.hostId,
      adapterType: "cursor",
      displayName: this.#displayName,
      enabled: this.#enabled,
      capabilities: { ...CURSOR_HOST_CAPABILITIES },
      version: "wp-04",
      metadata: { mode: "off", wraps: "CursorSdkAdapter" },
    };
  }

  prepareSession(input: PrepareSessionInput): Promise<PreparedHostSession> {
    return this.#inner.prepareSession(input);
  }

  inspectSession(reference: HostSessionRef): Promise<HostSessionState> {
    return this.#inner.inspectSession(reference);
  }

  startRun(session: HostSessionRef, input: StartRunInput): Promise<HostRunRef> {
    return this.#inner.startRun(session, input);
  }

  async *streamEvents(run: HostRunRef): AsyncIterable<HostEventEnvelope> {
    // Re-stream via inner, then remap with CursorHostEventMapper for stable Host types.
    // Inner already yields Host envelopes; we prefer mapping from raw RuntimeEvent when present.
    for await (const evt of this.#inner.streamEvents(run)) {
      const raw = evt.raw as RuntimeEvent | undefined;
      if (raw && typeof raw === "object" && "event_type" in raw) {
        yield mapCursorRuntimeEventToHostEnvelope({
          hostId: this.hostId,
          workerId: evt.workerId,
          runId: evt.runId,
          event: raw,
        });
      } else {
        yield evt;
      }
    }
  }

  cancelRun(run: HostRunRef, reason: string): Promise<void> {
    return this.#inner.cancelRun(run, reason);
  }

  async closeSession(reference: HostSessionRef): Promise<void> {
    const closer = (this.#inner as AgentHostAdapter).closeSession;
    if (typeof closer === "function") {
      await closer.call(this.#inner, reference);
    }
  }

  classifyError(error: unknown): HostFailure {
    return classifyCursorHostFailure(error);
  }
}
