import { For, Match, Show, Switch } from "solid-js"
import { RGBA, addDefaultParsers } from "@opentui/core"
import type { AssistantMessage, UserMessage } from "@saeeol/sdk/v2"
import { Prompt } from "@tui/component/prompt"
import { useCommandDialog } from "@tui/component/dialog-command"
import { DialogMessage } from "./dialog-message"
import { Sidebar } from "./sidebar"
import { SubagentFooter } from "./subagent-footer.tsx"
import { PermissionPrompt } from "./permission"
import { QuestionPrompt } from "./question"
import { SuggestPrompt } from "@/saeeol/suggestion/tui/prompt"
import { NetworkPrompt } from "./network"
import { TuiPluginRuntime } from "@/cli/cmd/tui/plugin/runtime"
import { SessionIndexing } from "@/saeeol/components/session-indexing"
import { Toast } from "../../ui/toast"
import { context } from "./context"
import { UserMessage as UserMessageComponent } from "./messages/user-message"
import { AssistantMessage as AssistantMessageComponent } from "./messages/assistant-message"
import { createSessionSetup } from "./session-setup"
import { registerSessionCommands } from "./session-commands"
import { RevertBanner } from "./session-revert-banner"
import parsers from "../../../../../../parsers-config.ts"

addDefaultParsers(parsers.parsers)

export function Session() {
  const s = createSessionSetup()
  const command = useCommandDialog()

  registerSessionCommands(command, {
    session: s.session,
    messages: s.messages,
    route: s.route,
    get scroll() { return s.refs.scroll! },
    get prompt() { return s.refs.prompt },
    children: s.ch,
    sync: s.sync,
    sdk: s.sdk,
    toast: s.toast,
    kv: s.kv,
    dialog: s.dialog,
    renderer: s.renderer,
    keybind: s.keybind,
    local: s.local,
    navigate: s.navigate,
    sidebarVisible: s.sidebarVisible,
    setSidebar: s.setSidebar,
    setSidebarOpen: s.setSidebarOpen,
    setConceal: s.setConceal,
    setTimestamps: s.setTimestamps,
    setShowThinking: s.setShowThinking,
    setShowDetails: s.setShowDetails,
    setShowScrollbar: s.setShowScrollbar,
    setShowGenericToolOutput: s.setShowGenericToolOutput,
    showThinking: s.showThinking,
    showDetails: s.showDetails,
    showAssistantMetadata: s.showAssistantMetadata,
    conceal: s.conceal,
    showTimestamps: s.showTimestamps,
    showGenericToolOutput: s.showGenericToolOutput,
    toBottom: s.toBottom,
    pointing: s.pointing,
    setPointing: s.setPointing,
  })

  return (
    <context.Provider
      value={{
        get width() { return s.contentWidth() },
        sessionID: s.route.sessionID,
        conceal: s.conceal, showThinking: s.showThinking, showTimestamps: s.showTimestamps,
        showDetails: s.showDetails, showGenericToolOutput: s.showGenericToolOutput,
        diffWrapMode: s.diffWrapMode, providers: s.providers, sync: s.sync, tui: s.tuiConfig,
      }}
    >
      <box flexDirection="row">
        <box flexGrow={1} paddingBottom={1} paddingLeft={2} paddingRight={2} gap={1}>
          <Show when={s.session()}>
            <scrollbox
              ref={(r) => { s.refs.scroll = r }}
              viewportOptions={{ paddingRight: s.showScrollbar() ? 1 : 0 }}
              verticalScrollbarOptions={{
                paddingLeft: 1,
                visible: s.showScrollbar(),
                trackOptions: { backgroundColor: s.theme.backgroundElement, foregroundColor: s.theme.border },
              }}
              stickyScroll={true}
              stickyStart="bottom"
              flexGrow={1}
              scrollAcceleration={s.scrollAcceleration()}
            >
              <box height={1} />
              <Show when={s.session()?.parentID && s.messages().length === 0}>
                <box paddingLeft={3}>
                  <text fg={s.theme.textMuted}>↳ Initializing...</text>
                </box>
              </Show>
              <For each={s.messages()}>
                {(message, index) => (
                  <Switch>
                    <Match when={message.id === s.revert()?.messageID}>
                      <RevertBanner revert={s.revert()!} />
                    </Match>
                    <Match when={s.revert()?.messageID && message.id >= s.revert()!.messageID}>
                      <></>
                    </Match>
                    <Match when={message.role === "user"}>
                      <UserMessageComponent
                        index={index()}
                        onMouseUp={() => {
                          if (s.renderer.getSelection()?.getSelectedText()) return
                          s.dialog.replace(() => <DialogMessage messageID={message.id} sessionID={s.route.sessionID} setPrompt={(pi) => s.refs.prompt?.set(pi)} />)
                        }}
                        message={message as UserMessage}
                        parts={s.sync.data.part[message.id] ?? []}
                        pending={s.pending()}
                      />
                    </Match>
                    <Match when={message.role === "assistant"}>
                      <AssistantMessageComponent
                        last={s.lastAssistant()?.id === message.id}
                        message={message as AssistantMessage}
                        parts={s.sync.data.part[message.id] ?? []}
                      />
                    </Match>
                  </Switch>
                )}
              </For>
            </scrollbox>
            <box flexShrink={0}>
              <Show when={s.permissions().length > 0}>
                <PermissionPrompt request={s.permissions()[0]} />
              </Show>
              <Show when={s.permissions().length === 0 && s.question()} keyed>
                {(request) => <QuestionPrompt request={request} nonBlocking={request.blocking === false} inputFocused={() => s.refs.prompt?.focused ?? false} />}
              </Show>
              <Show when={s.permissions().length === 0 && !s.question()}>
                <Show when={s.blockingSuggestion()} keyed>
                  {(request) => <SuggestPrompt request={request} />}
                </Show>
              </Show>
              <Show when={s.session()?.parentID}>
                <SubagentFooter />
              </Show>
              <Show when={s.networkVisible()}>
                <NetworkPrompt request={s.network()[0]} />
              </Show>
              <Show when={!s.session()?.parentID}>
                <TuiPluginRuntime.Slot name="session_prompt" mode="replace" session_id={s.route.sessionID} visible={s.visible()} disabled={s.disabled()} on_submit={s.toBottom} ref={s.bind}>
                  <Prompt
                    visible={s.visible()}
                    ref={s.bind}
                    disabled={s.disabled()}
                    onSubmit={() => s.toBottom()}
                    sessionID={s.route.sessionID}
                    right={
                      <box flexDirection="row" gap={1} alignItems="center">
                        <text fg={s.theme.textMuted} onMouseDown={() => { const vis = s.sidebarVisible(); s.setSidebar(() => (vis ? "hide" : "auto")); s.setSidebarOpen(!vis) }}>
                          {s.sidebarVisible() ? "◂" : "▸"}
                        </text>
                        <text fg={s.theme.textMuted} onMouseDown={() => s.toBottom()}>↓</text>
                        <TuiPluginRuntime.Slot name="session_prompt_right" session_id={s.route.sessionID} />
                      </box>
                    }
                  />
                </TuiPluginRuntime.Slot>
              </Show>
            </box>
          </Show>
          <SessionIndexing />
          <Toast />
        </box>
        <Show when={s.sidebarVisible()}>
          <Switch>
            <Match when={s.wide()}>
              <Sidebar sessionID={s.route.sessionID} />
            </Match>
            <Match when={!s.wide()}>
              <box position="absolute" top={0} left={0} right={0} bottom={0} alignItems="flex-end" backgroundColor={RGBA.fromInts(0, 0, 0, 70)}>
                <Sidebar sessionID={s.route.sessionID} />
              </box>
            </Match>
          </Switch>
        </Show>
      </box>
    </context.Provider>
  )
}
