import type { ToolPart } from "@opencode-ai/sdk/v2/client"
import { test, expect } from "../fixtures"
import { closeDialog, openSettings, withSession } from "../actions"
import { promptModelSelector, promptSelector, promptVariantSelector } from "../selectors"

const isBash = (part: unknown): part is ToolPart => {
  if (!part || typeof part !== "object") return false
  if (!("type" in part) || part.type !== "tool") return false
  if (!("tool" in part) || part.tool !== "bash") return false
  return "state" in part
}

test("shell mode runs a command in the project directory", async ({ page, project }) => {
  test.setTimeout(120_000)

  await project.open()
  const cmd = process.platform === "win32" ? "dir" : "command ls"

  await withSession(project.sdk, `e2e shell ${Date.now()}`, async (session) => {
    project.trackSession(session.id)
    await project.gotoSession(session.id)
    const dialog = await openSettings(page)
    const toggle = dialog.locator('[data-action="settings-auto-accept-permissions"]').first()
    const input = toggle.locator('[data-slot="switch-input"]').first()
    await expect(toggle).toBeVisible()
    if ((await input.getAttribute("aria-checked")) !== "true") {
      await toggle.locator('[data-slot="switch-control"]').click()
      await expect(input).toHaveAttribute("aria-checked", "true")
    }
    await closeDialog(page, dialog)
    await project.shell(cmd)

    await expect
      .poll(
        async () => {
          const list = await project.sdk.session
            .messages({ sessionID: session.id, limit: 50 })
            .then((x) => x.data ?? [])
          const msg = list.findLast(
            (item) => item.info.role === "assistant" && "path" in item.info && item.info.path.cwd === project.directory,
          )
          if (!msg) return

          const part = msg.parts
            .filter(isBash)
            .find((item) => item.state.input?.command === cmd && item.state.status === "completed")

          if (!part || part.state.status !== "completed") return
          const output =
            typeof part.state.metadata?.output === "string" ? part.state.metadata.output : part.state.output
          if (!output.includes("README.md")) return

          return { cwd: project.directory, output }
        },
        { timeout: 90_000 },
      )
      .toEqual(expect.objectContaining({ cwd: project.directory, output: expect.stringContaining("README.md") }))
  })
})

test("shell mode unmounts model and variant controls", async ({ page, project }) => {
  await project.open()

  const prompt = page.locator(promptSelector).first()
  await expect(page.locator(promptModelSelector)).toHaveCount(1)
  await expect(page.locator(promptVariantSelector)).toHaveCount(1)

  await prompt.click()
  await page.keyboard.type("!")

  await expect(prompt).toHaveAttribute("aria-label", /enter shell command/i)
  await expect(page.locator(promptModelSelector)).toHaveCount(0)
  await expect(page.locator(promptVariantSelector)).toHaveCount(0)
})
