import type { NavigateFunction } from 'react-router-dom'
import { ISLANDER_CONFIG } from './config'
import { executeIslanderActions } from './actionExecutor'
import {
  formatActionResults,
  parseIslanderActions,
  stripIslanderActions,
} from './islanderActions'
import { capturePageSnapshot } from './pageSnapshot'
import type { IslanderChatTurn, PageSnapshot } from './types'

export type IslanderStreamChat = (
  messages: IslanderChatTurn[],
  context: string,
  onDelta: (delta: string) => void,
) => Promise<void>

export type IslanderAgentCallbacks = {
  onSystemMessage: (content: string) => string
  onSystemMessageUpdate: (id: string, content: string) => void
  onAssistantDelta: (assistantId: string, visibleContent: string) => void
  onAssistantStart: () => string
  onActingChange?: (acting: boolean) => void
}

export type BuildIslanderContextFn = (opts: { includePageDetail: boolean }) => string

export type RunIslanderAgentOptions = {
  history: IslanderChatTurn[]
  assistantId: string
  buildContext: BuildIslanderContextFn
  initialIncludePageDetail: boolean
  /** Snapshot captured when the user sent the message; keeps hx-* refs aligned with AI context. */
  pageSnapshot?: PageSnapshot
  navigate: NavigateFunction
  streamChat: IslanderStreamChat
  callbacks: IslanderAgentCallbacks
  maxRounds?: number
}

const FOLLOW_UP_PROMPT = [
  '【系統｜操作結果】',
  '{{results}}',
  '',
  '【更新後可互動元素】',
  '{{snapshot}}',
  '',
  '若任務尚未完成，請繼續操作。若已 fill/click 完成，用人話說已幫他填好或點好即可；禁止在正文輸出 JSON 或 action 說明。',
].join('\n')

async function streamAssistant(
  history: IslanderChatTurn[],
  assistantId: string,
  context: string,
  streamChat: IslanderStreamChat,
  onDelta: (assistantId: string, visibleContent: string) => void,
): Promise<string> {
  let raw = ''
  await streamChat(history, context, (delta) => {
    raw += delta
    onDelta(assistantId, stripIslanderActions(raw))
  })
  return raw
}

async function runAgentFollowUp(
  history: IslanderChatTurn[],
  rawAssistantContent: string,
  opts: RunIslanderAgentOptions,
  round: number,
): Promise<void> {
  const actions = parseIslanderActions(rawAssistantContent)
  const maxRounds = opts.maxRounds ?? ISLANDER_CONFIG.maxAgentRounds
  if (actions.length === 0 || round >= maxRounds) return

  const systemId = opts.callbacks.onSystemMessage('島民正在幫你操作頁面…')
  opts.callbacks.onActingChange?.(true)

  try {
    const actionSnapshot =
      round === 0 && opts.pageSnapshot ? opts.pageSnapshot : capturePageSnapshot()

    const { results, snapshotText } = await executeIslanderActions({
      actions,
      navigate: opts.navigate,
      snapshot: actionSnapshot,
    })

    opts.callbacks.onSystemMessageUpdate(systemId, `已執行 ${results.length} 個操作`)

    const followUpUser: IslanderChatTurn = {
      role: 'user',
      content: FOLLOW_UP_PROMPT.replace('{{results}}', formatActionResults(results)).replace(
        '{{snapshot}}',
        snapshotText,
      ),
    }

    const nextHistory: IslanderChatTurn[] = [
      ...history,
      { role: 'assistant', content: stripIslanderActions(rawAssistantContent) },
      followUpUser,
    ]

    const followAssistantId = opts.callbacks.onAssistantStart()
    const followRaw = await streamAssistant(
      nextHistory,
      followAssistantId,
      opts.buildContext({ includePageDetail: true }),
      opts.streamChat,
      opts.callbacks.onAssistantDelta,
    )

    await runAgentFollowUp(nextHistory, followRaw, opts, round + 1)
  } catch {
    opts.callbacks.onSystemMessageUpdate(systemId, '操作失敗，請再試一次')
  } finally {
    opts.callbacks.onActingChange?.(false)
  }
}

/** Run one user turn: stream reply, execute actions, auto follow-up until done. */
export async function runIslanderAgentTurn(opts: RunIslanderAgentOptions): Promise<void> {
  const raw = await streamAssistant(
    opts.history,
    opts.assistantId,
    opts.buildContext({ includePageDetail: opts.initialIncludePageDetail }),
    opts.streamChat,
    opts.callbacks.onAssistantDelta,
  )
  await runAgentFollowUp(opts.history, raw, opts, 0)
}