import type { AgentSdkAdapter } from "../../registry/AgentSdkAdapter.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";

export const CODEX_CLI_HOST_CAPABILITIES = normalizeHostCapabilities({
  level: "H2",
  persistentSession: false,
  resumableSession: false,
  structuredEvents: true,
  cancellableRun: true,
  inspectableSession: true,
  workspaceBinding: true,
  concurrentWorkers: true,
  extensions: {
    transport: "codex-cli-jsonl",
    model_provider: "runtime-selected",
    switchboard_mode: "shadow",
    tools: true,
    mcp: true,
  },
});

export interface CodexCliHostAdapterOptions extends LegacySdkHostAdapterOptions {
  hostId?: string;
  providerMode?: "chatgpt-subscription" | "custom-provider";
  modelProvider?: string;
}

/** Host-neutral wrapper for the Codex CLI execution harness. */
export class CodexCliHostAdapter implements AgentHostAdapter {
  readonly hostId: string;
  readonly #inner: LegacySdkHostAdapter;
  readonly #displayName: string;
  readonly #enabled: boolean;
  readonly #providerMode: "chatgpt-subscription" | "custom-provider";
  readonly #modelProvider: string;

  constructor(sdk: AgentSdkAdapter, options: CodexCliHostAdapterOptions = {}) {
    this.#providerMode = options.providerMode ?? "custom-provider";
    this.#modelProvider = options.modelProvider?.trim() || (
      this.#providerMode === "chatgpt-subscription" ? "openai-chatgpt-subscription" : "volcengine-ark"
    );
    this.hostId = options.hostId?.trim() || (
      this.#providerMode === "chatgpt-subscription"
        ? "host-codex-cli-subscription"
        : "host-codex-cli-doubao"
    );
    this.#displayName = options.displayName?.trim() || (
      this.#providerMode === "chatgpt-subscription"
        ? "Codex CLI + ChatGPT Subscription Host"
        : "Codex CLI + Doubao Host"
    );
    this.#enabled = options.enabled !== false;
    this.#inner = new LegacySdkHostAdapter(sdk, {
      ...options,
      hostId: this.hostId,
      displayName: this.#displayName,
      enabled: this.#enabled,
    });
  }

  get underlyingSdkAdapter(): AgentSdkAdapter { return this.#inner.underlyingSdkAdapter; }

  async describe(): Promise<HostDescriptor> {
    return {
      hostId: this.hostId,
      adapterType: this.#providerMode === "chatgpt-subscription"
        ? "codex-cli-subscription"
        : "codex-cli-custom-provider",
      displayName: this.#displayName,
      enabled: this.#enabled,
      capabilities: { ...CODEX_CLI_HOST_CAPABILITIES },
      version: "1.3.1",
      metadata: {
        mode: "shadow",
        execution_harness: "codex-cli",
        model_provider: this.#modelProvider,
        auth_mode: this.#providerMode,
      },
    };
  }

  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);
  }
  streamEvents(run: HostRunRef): AsyncIterable<HostEventEnvelope> {
    return this.#inner.streamEvents(run);
  }
  cancelRun(run: HostRunRef, reason: string): Promise<void> {
    return this.#inner.cancelRun(run, reason);
  }
  classifyError(error: unknown): HostFailure {
    const message = error instanceof Error ? error.message : String(error);
    if (/NOT_FOUND|not found|WindowsApps|PROBE_FAILED/i.test(message)) {
      return { kind: "provider_unavailable", message, retryable: false, raw: error };
    }
    if (/401|403|api[_ -]?key|unauthorized|forbidden/i.test(message)) {
      return { kind: "permission", message, retryable: false, raw: error };
    }
    return this.#inner.classifyError(error);
  }
}
