import {
  type AgentSideConnection,
  type AuthenticateRequest,
  type InitializeRequest,
  type InitializeResponse,
  type ListSessionsRequest,
  type ListSessionsResponse,
  type LoadSessionRequest,
  type NewSessionRequest,
  type ForkSessionRequest,
  type ForkSessionResponse,
  type ResumeSessionRequest,
  type ResumeSessionResponse,
  type CancelNotification,
  type SetSessionModelRequest,
  type SetSessionModeRequest,
  type SetSessionModeResponse,
  type SetSessionConfigOptionRequest,
  type SetSessionConfigOptionResponse,
  type PromptRequest,
  type PermissionOption,
} from "@agentclientprotocol/sdk"
import { ACPSessionManager } from "./session"
import type { ACPConfig } from "./types"
import type { AgentDeps } from "./agent-types"
import { initialize, newSession, loadSession, listSessions, forkSession, resumeSession } from "./agent-session"
import { startEventSubscription } from "./agent-events"
import { prompt, cancel, setSessionModel, setSessionMode, setSessionConfigOption } from "./agent-prompt"

export type { ModeOption, ModelOption } from "./agent-types"

async function init({ sdk: _sdk }: { sdk: any }) {
  return { create: (connection: AgentSideConnection, fullConfig: ACPConfig) => new Agent(connection, fullConfig) }
}

class Agent {
  private connection: AgentSideConnection
  private config: ACPConfig
  private sdk: any
  private sessionManager: ACPSessionManager
  private eventAbort = new AbortController()
  private eventStarted = false
  private bashSnapshots = new Map<string, string>()
  private toolStarts = new Set<string>()
  private permissionQueues = new Map<string, Promise<void>>()
  private permissionOptions: PermissionOption[] = [
    { optionId: "once", kind: "allow_once", name: "Allow once" },
    { optionId: "always", kind: "allow_always", name: "Always allow" },
    { optionId: "reject", kind: "reject_once", name: "Reject" },
  ]

  constructor(connection: AgentSideConnection, config: ACPConfig) {
    this.connection = connection
    this.config = config
    this.sdk = config.sdk
    this.sessionManager = new ACPSessionManager(this.sdk)
    startEventSubscription(this.deps, this.eventAbort, { value: false })
    this.eventStarted = true
  }

  private get deps(): AgentDeps {
    return {
      connection: this.connection,
      config: this.config,
      sdk: this.sdk,
      sessionManager: this.sessionManager,
      permissionOptions: this.permissionOptions,
      bashSnapshots: this.bashSnapshots,
      toolStarts: this.toolStarts,
      permissionQueues: this.permissionQueues,
    }
  }

  async initialize(params: InitializeRequest) { return initialize(params) }
  async authenticate(_params: AuthenticateRequest) { throw new Error("Authentication not implemented") }
  async newSession(params: NewSessionRequest) { return newSession(this.deps, params) }
  async loadSession(params: LoadSessionRequest) { return loadSession(this.deps, params) }
  async listSessions(params: ListSessionsRequest): Promise<ListSessionsResponse> { return listSessions(this.deps, params) }
  async unstable_forkSession(params: ForkSessionRequest): Promise<ForkSessionResponse> { return forkSession(this.deps, params) }
  async unstable_resumeSession(params: ResumeSessionRequest): Promise<ResumeSessionResponse> { return resumeSession(this.deps, params) }
  async unstable_setSessionModel(params: SetSessionModelRequest) { return setSessionModel(this.deps, params) }
  async setSessionMode(params: SetSessionModeRequest): Promise<SetSessionModeResponse | void> { return setSessionMode(this.deps, params) }
  async setSessionConfigOption(params: SetSessionConfigOptionRequest): Promise<SetSessionConfigOptionResponse> { return setSessionConfigOption(this.deps, params) }
  async prompt(params: PromptRequest) { return prompt(this.deps, params) }
  async cancel(params: CancelNotification) { return cancel(this.deps, params) }
}

export { init, Agent }
export * as ACP from "./agent"
