import { useEffect, useRef, useState } from 'react'
import { Settings2, Plus, X, Columns2, Grid2x2, SquareSlash, Sparkles } from 'lucide-react'
import { api, type Integration, type PromptPreset, type PromptStatus } from '../lib/api'
import { useTerminalSessions } from '../lib/TerminalSessionContext'
import { TERM_THEMES } from '../lib/terminalPrefs'

const GOLD = '#C8A434'
const TEXT_SECONDARY = '#7A7D85'

const FONT_SIZES = [11, 12, 13, 14, 15, 16]
// "Symbols Nerd Font Mono" is appended as a glyph-only fallback to every option, so
// distro icons / git branch / etc. from prompts like Starship render instead of
// showing as boxes — it has no letterforms of its own, so it never overrides the
// chosen base font for normal text.
const NERD_FALLBACK = '"Symbols Nerd Font Mono"'
const FONT_FAMILIES = [
  { name: 'Monospace', value: `ui-monospace, SFMono-Regular, Menlo, monospace, ${NERD_FALLBACK}` },
  { name: 'Fira Code', value: `"Fira Code", ui-monospace, monospace, ${NERD_FALLBACK}` },
  { name: 'JetBrains Mono', value: `"JetBrains Mono", ui-monospace, monospace, ${NERD_FALLBACK}` },
]

export default function Terminal() {
  const [hosts, setHosts] = useState<Integration[]>([])
  const [showPrefs, setShowPrefs] = useState(false)

  const {
    tabs,
    activeTabId,
    activePaneId,
    prefs,
    setActiveTabId,
    setActivePaneId,
    setPrefs,
    addTab,
    closeTab,
    setPaneCount,
    setPaneHost,
  } = useTerminalSessions()

  useEffect(() => {
    api.listIntegrations().then(({ integrations }) => {
      setHosts(integrations.filter((i) => i.type === 'ssh'))
    })
  }, [])

  const activeTab = tabs.find((t) => t.id === activeTabId) ?? tabs[0]

  const paneGridClass =
    activeTab.panes.length === 1
      ? 'grid-cols-1 grid-rows-1'
      : activeTab.panes.length === 2
        ? 'grid-cols-2 grid-rows-1'
        : 'grid-cols-2 grid-rows-2'

  const activePaneHostId = activeTab.panes.find((p) => p.id === activePaneId)?.hostId ?? null

  return (
    <div className="flex h-full gap-4">
      <div className="w-56 shrink-0 overflow-y-auto rounded-lg border border-white/10 bg-white/5 p-3">
        <p className="mb-2 text-xs font-medium uppercase tracking-wide" style={{ color: TEXT_SECONDARY }}>
          SSH Hosts
        </p>
        {hosts.length === 0 && (
          <p className="text-xs" style={{ color: TEXT_SECONDARY }}>
            No SSH integrations configured. Add one in Settings → Integrations.
          </p>
        )}
        <div className="flex flex-col gap-1">
          {hosts.map((h) => (
            <button
              key={h.id}
              onClick={() => activePaneId !== null && setPaneHost(activePaneId, h.id)}
              className="rounded-md px-2 py-1.5 text-left text-sm transition-colors"
              style={{
                background: activePaneHostId === h.id ? 'rgba(200,164,52,0.15)' : 'transparent',
                color: activePaneHostId === h.id ? GOLD : '#E8E6E0',
              }}
            >
              {h.name}
            </button>
          ))}
        </div>
        <p className="mt-3 text-[11px]" style={{ color: TEXT_SECONDARY }}>
          Click a pane, then a host to connect it. Sessions stay connected when
          you switch pages — close a tab or pane to disconnect.
        </p>
      </div>

      <div className="flex min-w-0 flex-1 flex-col gap-2">
        <div className="flex items-center gap-2">
          <div className="flex flex-1 items-center gap-1 overflow-x-auto">
            {tabs.map((tab) => (
              <div
                key={tab.id}
                onClick={() => setActiveTabId(tab.id)}
                className="flex shrink-0 cursor-pointer items-center gap-2 rounded-md px-3 py-1.5 text-xs"
                style={{
                  background: tab.id === activeTabId ? 'rgba(200,164,52,0.15)' : 'rgba(255,255,255,0.04)',
                  color: tab.id === activeTabId ? GOLD : '#E8E6E0',
                }}
              >
                {tab.name}
                <X
                  size={12}
                  onClick={(e) => {
                    e.stopPropagation()
                    closeTab(tab.id)
                  }}
                />
              </div>
            ))}
            <button onClick={addTab} className="shrink-0 rounded-md p-1.5" style={{ color: TEXT_SECONDARY }} title="New tab">
              <Plus size={14} />
            </button>
          </div>

          <div className="flex items-center gap-1">
            <button onClick={() => setPaneCount(1)} className="rounded-md p-1.5" style={{ color: activeTab.panes.length === 1 ? GOLD : TEXT_SECONDARY }} title="Single pane">
              <SquareSlash size={14} />
            </button>
            <button onClick={() => setPaneCount(2)} className="rounded-md p-1.5" style={{ color: activeTab.panes.length === 2 ? GOLD : TEXT_SECONDARY }} title="Split 2">
              <Columns2 size={14} />
            </button>
            <button onClick={() => setPaneCount(4)} className="rounded-md p-1.5" style={{ color: activeTab.panes.length === 4 ? GOLD : TEXT_SECONDARY }} title="Split 4">
              <Grid2x2 size={14} />
            </button>
            <button onClick={() => setShowPrefs((v) => !v)} className="rounded-md p-1.5" style={{ color: showPrefs ? GOLD : TEXT_SECONDARY }} title="Terminal preferences">
              <Settings2 size={14} />
            </button>
          </div>
        </div>

        {showPrefs && (
          <div className="flex items-center gap-4 rounded-lg border border-white/10 bg-white/5 px-3 py-2 text-xs" style={{ color: '#E8E6E0' }}>
            <label className="flex items-center gap-2">
              Theme
              <select
                value={prefs.themeName}
                onChange={(e) => setPrefs((p) => ({ ...p, themeName: e.target.value }))}
                className="rounded-md border border-white/10 bg-transparent px-2 py-1"
              >
                {TERM_THEMES.map((t) => (
                  <option key={t.name} value={t.name}>
                    {t.name}
                  </option>
                ))}
              </select>
            </label>
            <label className="flex items-center gap-2">
              Font Size
              <select
                value={prefs.fontSize}
                onChange={(e) => setPrefs((p) => ({ ...p, fontSize: Number(e.target.value) }))}
                className="rounded-md border border-white/10 bg-transparent px-2 py-1"
              >
                {FONT_SIZES.map((s) => (
                  <option key={s} value={s}>
                    {s}px
                  </option>
                ))}
              </select>
            </label>
            <label className="flex items-center gap-2">
              Font
              <select
                value={prefs.fontFamily}
                onChange={(e) => setPrefs((p) => ({ ...p, fontFamily: e.target.value }))}
                className="rounded-md border border-white/10 bg-transparent px-2 py-1"
              >
                {FONT_FAMILIES.map((f) => (
                  <option key={f.name} value={f.value}>
                    {f.name}
                  </option>
                ))}
              </select>
            </label>
            <div className="ml-auto border-l border-white/10 pl-4">
              <ShellPromptControl hostId={activePaneHostId} />
            </div>
          </div>
        )}

        <div className={`grid min-h-0 flex-1 gap-3 ${paneGridClass}`}>
          {activeTab.panes.map((pane) => (
            <TerminalPane
              key={pane.id}
              paneId={pane.id}
              hostId={pane.hostId}
              hosts={hosts}
              active={pane.id === activePaneId}
              onFocus={() => setActivePaneId(pane.id)}
            />
          ))}
        </div>
      </div>
    </div>
  )
}

function TerminalPane({
  paneId,
  hostId,
  hosts,
  active,
  onFocus,
}: {
  paneId: number
  hostId: number | null
  hosts: Integration[]
  active: boolean
  onFocus: () => void
}) {
  const { attachPane, getPaneInfo, reconnectTmux, version } = useTerminalSessions()
  const cellRef = useRef<HTMLDivElement>(null)

  // Mount the persistent xterm DOM node owned by the provider into this cell;
  // on unmount (route change or layout change) the wrapper is moved back to the
  // hidden root rather than disposed, so the session keeps running.
  useEffect(() => {
    if (!cellRef.current) return
    const detach = attachPane(paneId, cellRef.current)
    return detach
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [paneId])

  // `version` is read so the header re-renders when live pane state changes.
  void version
  const info = getPaneInfo(paneId)
  const host = hosts.find((h) => h.id === hostId)

  return (
    <div
      onClick={onFocus}
      className="flex min-w-0 min-h-0 flex-col rounded-lg p-3"
      style={{
        backgroundColor: '#15161A',
        border: active ? `1px solid ${GOLD}` : '1px solid rgba(255,255,255,0.1)',
      }}
    >
      <div className="mb-3 flex items-center gap-2 px-2 text-xs" style={{ color: TEXT_SECONDARY }}>
        <span className="inline-block h-2 w-2 rounded-full" style={{ background: info.connected ? '#2ECC71' : '#7A7D85' }} />
        {host ? (info.connected ? `Connected — ${host.name}` : `Disconnected — ${host.name}`) : 'Select a host to connect'}
        {host && (
          <select
            value={info.selectedTmux}
            onClick={(e) => e.stopPropagation()}
            onChange={(e) => reconnectTmux(paneId, e.target.value)}
            className="ml-auto rounded-md border border-white/10 bg-transparent px-1.5 py-0.5"
            style={{ color: TEXT_SECONDARY, fontSize: '11px' }}
            title="Attach to a tmux session on this host"
          >
            <option value="">Plain shell</option>
            <option value="__new__">New tmux session</option>
            {info.tmuxSessions.map((s) => (
              <option key={s} value={s}>
                tmux: {s}
              </option>
            ))}
          </select>
        )}
      </div>
      <div className="min-h-0 flex-1" style={{ padding: '0 6px' }}>
        <div ref={cellRef} className="h-full w-full" />
      </div>
    </div>
  )
}

/**
 * Lets a user pick one of a few Starship prompt looks and install it (Starship
 * + a Nerd Font, if not already present) on the active pane's SSH host with
 * one click, instead of running a script by hand.
 */
function ShellPromptControl({ hostId }: { hostId: number | null }) {
  const [presets, setPresets] = useState<PromptPreset[]>([])
  const [status, setStatus] = useState<PromptStatus | null>(null)
  const [selected, setSelected] = useState('')
  const [installing, setInstalling] = useState(false)
  const [message, setMessage] = useState<string | null>(null)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    setStatus(null)
    setMessage(null)
    setError(null)
    if (hostId === null) return
    api
      .getShellPromptStatus(hostId)
      .then(({ presets, status }) => {
        setPresets(presets)
        setStatus(status)
        setSelected(status.configuredPreset ?? presets[0]?.id ?? '')
      })
      .catch((err) => setError(err instanceof Error ? err.message : 'Failed to check host'))
  }, [hostId])

  if (hostId === null) {
    return <span style={{ color: TEXT_SECONDARY }}>Connect a host to set up its shell prompt</span>
  }

  async function handleInstall() {
    if (!selected) return
    setInstalling(true)
    setError(null)
    setMessage(null)
    try {
      await api.installShellPrompt(hostId!, selected)
      setMessage('Installed — open a new terminal session to this host to see it.')
      const { status } = await api.getShellPromptStatus(hostId!)
      setStatus(status)
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Install failed')
    } finally {
      setInstalling(false)
    }
  }

  return (
    <div className="flex items-center gap-2">
      <Sparkles size={13} style={{ color: GOLD }} />
      <label className="flex items-center gap-2">
        Shell Prompt
        <select
          value={selected}
          onChange={(e) => setSelected(e.target.value)}
          className="rounded-md border border-white/10 bg-transparent px-2 py-1"
        >
          {presets.map((p) => (
            <option key={p.id} value={p.id} title={p.description}>
              {p.name}
            </option>
          ))}
        </select>
      </label>
      <button
        onClick={handleInstall}
        disabled={installing || !selected}
        className="rounded-md px-2.5 py-1 text-xs font-medium"
        style={{ backgroundColor: GOLD, color: '#0A0A0C', opacity: installing ? 0.6 : 1 }}
      >
        {installing ? 'Installing…' : status?.configuredPreset === selected ? 'Reinstall' : 'Install'}
      </button>
      {message && <span style={{ color: '#2ECC71' }}>{message}</span>}
      {error && <span style={{ color: '#E74C3C' }}>{error}</span>}
    </div>
  )
}
