import { createStore, produce } from "solid-js/store"
import { createSimpleContext } from "@opencode-ai/ui/context"
import { batch, createMemo } from "solid-js"
import { makePersisted } from "@solid-primitives/storage"
import { useParams } from "@solidjs/router"
import { useSDK } from "./sdk"

export type LocalPTY = {
  id: string
  title: string
  rows?: number
  cols?: number
  buffer?: string
  scrollY?: number
}

export const { use: useTerminal, provider: TerminalProvider } = createSimpleContext({
  name: "Terminal",
  init: () => {
    const sdk = useSDK()
    const params = useParams()
    const name = createMemo(() => `${params.dir}/terminal${params.id ? "/" + params.id : ""}.v1`)

    const [store, setStore] = makePersisted(
      createStore<{
        active?: string
        all: LocalPTY[]
      }>({
        all: [],
      }),
      {
        name: name(),
      },
    )

    return {
      all: createMemo(() => Object.values(store.all)),
      active: createMemo(() => store.active),
      new() {
        sdk.client.pty.create({ title: `Terminal ${store.all.length + 1}` }).then((pty) => {
          const id = pty.data?.id
          if (!id) return
          setStore("all", [
            ...store.all,
            {
              id,
              title: pty.data?.title ?? "Terminal",
            },
          ])
          setStore("active", id)
        })
      },
      update(pty: Partial<LocalPTY> & { id: string }) {
        setStore("all", (x) => x.map((x) => (x.id === pty.id ? { ...x, ...pty } : x)))
        sdk.client.pty.update({
          ptyID: pty.id,
          title: pty.title,
          size: pty.cols && pty.rows ? { rows: pty.rows, cols: pty.cols } : undefined,
        })
      },
      async clone(id: string) {
        const index = store.all.findIndex((x) => x.id === id)
        const pty = store.all[index]
        if (!pty) return
        const clone = await sdk.client.pty.create({
          title: pty.title,
        })
        if (!clone.data) return
        setStore("all", index, {
          ...pty,
          ...clone.data,
        })
        if (store.active === pty.id) {
          setStore("active", clone.data.id)
        }
      },
      open(id: string) {
        setStore("active", id)
      },
      async close(id: string) {
        batch(() => {
          setStore(
            "all",
            store.all.filter((x) => x.id !== id),
          )
          if (store.active === id) {
            const index = store.all.findIndex((f) => f.id === id)
            const previous = store.all[Math.max(0, index - 1)]
            setStore("active", previous?.id)
          }
        })
        await sdk.client.pty.remove({ ptyID: id })
      },
      move(id: string, to: number) {
        const index = store.all.findIndex((f) => f.id === id)
        if (index === -1) return
        setStore(
          "all",
          produce((all) => {
            all.splice(to, 0, all.splice(index, 1)[0])
          }),
        )
      },
    }
  },
})
