import type { AssistantMessage } from "@woozlit/sdk/v2"
import type { TuiPlugin, TuiPluginApi, TuiPluginModule } from "@woozlit/plugin/tui"
import { Show, createEffect, createMemo, createSignal, onCleanup } from "solid-js"
import { completedTPS, formatTPS, streamingTPS } from "./tps"

const id = "internal:sidebar-context"
const REFRESH_MS = 1000

const money = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
})

function View(props: { api: TuiPluginApi; session_id: string }) {
  const theme = () => props.api.theme.current
  const msg = createMemo(() => props.api.state.session.messages(props.session_id))
  const cost = createMemo(() => msg().reduce((sum, item) => sum + (item.role === "assistant" ? item.cost : 0), 0))

  const [tick, setTick] = createSignal(Date.now())

  const lastAssistant = createMemo(() =>
    msg().findLast((item): item is AssistantMessage => item.role === "assistant"),
  )

  const isStreaming = createMemo(() => {
    const m = lastAssistant()
    return m !== undefined && !m.time.completed
  })

  createEffect(() => {
    if (!isStreaming()) return
    const handle = setInterval(() => setTick(Date.now()), REFRESH_MS)
    onCleanup(() => clearInterval(handle))
  })

  const tps = createMemo<number | null>(() => {
    const m = lastAssistant()
    if (!m) return null

    if (isStreaming()) {
      tick() // reactivity dep so the readout updates between deltas
      const parts = props.api.state.part(m.id)
      const combined = parts
        .filter((p) => p.type === "text" || p.type === "reasoning")
        .map((p) => p.text)
        .join("")
      return streamingTPS(combined, m.time.created, Date.now())
    }

    const idleTarget = msg().findLast(
      (item): item is AssistantMessage =>
        item.role === "assistant" &&
        item.time.completed !== undefined &&
        item.tokens.output + item.tokens.reasoning > 0,
    )
    if (!idleTarget || idleTarget.time.completed === undefined) return null
    return completedTPS(
      idleTarget.tokens.output,
      idleTarget.tokens.reasoning,
      idleTarget.time.created,
      idleTarget.time.completed,
    )
  })

  const tpsLabel = createMemo(() => formatTPS(tps()))

  const [usageData, setUsageData] = createSignal<{ tokensUsed: number; monthlyLimit: number } | null>(null)

  const isWoozlitModel = createMemo(() => {
    const last = lastAssistant()
    return last?.providerID === "woozlit"
  })

  const fetchUsage = async () => {
    if (!isWoozlitModel()) {
      setUsageData(null)
      return
    }
    try {
      const res = await props.api.client.auth.get({ providerID: "woozlit" })
      const token = res.data?.auth?.type === "oauth" ? res.data.auth.access : null
      if (!token) return

      const baseUrl = process.env.WOOZLIT_BASE_URL || "https://www.woozlit.com"
      const response = await fetch(`${baseUrl}/api/user/usage`, {
        headers: {
          Authorization: `Bearer ${token}`
        }
      })
      if (response.ok) {
        const data = await response.json()
        setUsageData(data)
      }
    } catch (err) {
      // ignore
    }
  }

  createEffect(() => {
    msg().length
    fetchUsage()
  })

  const state = createMemo(() => {
    const last = msg().findLast((item): item is AssistantMessage => item.role === "assistant" && item.tokens.output > 0)
    if (!last) {
      return {
        tokens: 0,
        percent: null,
      }
    }

    const tokens =
      last.tokens.input + last.tokens.output + last.tokens.reasoning + last.tokens.cache.read + last.tokens.cache.write
    const model = props.api.state.provider.find((item) => item.id === last.providerID)?.models[last.modelID]
    return {
      tokens,
      percent: model?.limit.context ? Math.round((tokens / model.limit.context) * 100) : null,
    }
  })

  return (
    <box>
      <text fg={theme().text}>
        <b>Context</b>
      </text>
      <text fg={theme().textMuted}>{state().tokens.toLocaleString()} tokens</text>
      <text fg={theme().textMuted}>{state().percent ?? 0}% used</text>
      <Show when={tpsLabel()}>{(label) => <text fg={theme().textMuted}>{label()}</text>}</Show>
      <text fg={theme().textMuted}>{money.format(cost())} spent</text>
      <Show when={usageData()}>
        {(data) => (
          <box marginTop={1}>
            <text fg={theme().text}>
              <b>Monthly Usage</b>
            </text>
            <text fg={theme().textMuted}>
              {data().tokensUsed.toLocaleString()} / {data().monthlyLimit.toLocaleString()}
            </text>
            <text fg={theme().textMuted}>
              Left: {Math.max(0, data().monthlyLimit - data().tokensUsed).toLocaleString()}
            </text>
            <text fg={theme().textMuted}>
              {Math.round((data().tokensUsed / (data().monthlyLimit || 1)) * 100)}% monthly used
            </text>
          </box>
        )}
      </Show>
    </box>
  )
}

const tui: TuiPlugin = async (api) => {
  api.slots.register({
    order: 100,
    slots: {
      sidebar_content(_ctx, props) {
        return <View api={api} session_id={props.session_id} />
      },
    },
  })
}

const plugin: TuiPluginModule & { id: string } = {
  id,
  tui,
}

export default plugin
