import { useCallback, useEffect, useState } from 'react'
import {
  Activity,
  ChevronRight,
  Database,
  FolderTree,
  Loader2,
  Network,
  Play,
  RefreshCw,
  Server,
  Table2,
  TerminalSquare,
} from 'lucide-react'
import { Badge } from '../ui/Badge'
import { DbBrandIcon, dbBrandColor } from '../ui/DbBrandIcon'
import { DataBrowserGrid } from './DataBrowserGrid'
import { DataGenPanel } from './DataGenPanel'
import { DbShell } from './DbShell'
import { Neo4jGraphView } from './Neo4jGraphView'
import { SqlWorkbench } from './SqlWorkbench'
import { LakehouseWorkbench } from './SparkView'
import {
  getSourceMeta,
  SOURCE_CATALOG,
  type CatalogObject,
  type SourceEngine,
  type SourceSubTab,
} from '../../lib/dataSourceCatalog'
import { cn } from '../../lib/utils'
import { subTabActive, subTabIdle } from '../../lib/tabActive'

type HealthMap = Record<string, { ok: boolean; error?: string | null }>
type CatalogResponse = {
  engine: string
  version?: string
  total_nodes?: number
  objects: CatalogObject[]
}
type SampleResponse = {
  ok: boolean
  columns?: string[]
  rows?: unknown[][]
  row_count?: number
  elapsed_ms?: number
  error?: string
  primary_keys?: string[]
  cdc?: boolean
  editable?: boolean
  offset?: number
  limit?: number
  total_count?: number | null
}

type Props = {
  focusEngine?: SourceEngine | null
  onPulse?: () => void
}

const ENGINE_CATALOG: Record<SourceEngine, string | undefined> = {
  postgres: 'postgres_sales',
  mysql: 'mysql_hr',
  mongodb: 'mongodb_supplychain',
  cassandra: 'cassandra_telemetry',
  neo4j: undefined,
}

const SUB_TABS: { id: SourceSubTab; label: string; icon: typeof FolderTree; neo4jOnly?: boolean; hideNeo4j?: boolean }[] = [
  { id: 'browser', label: 'Browser', icon: FolderTree },
  { id: 'graph', label: 'Graph', icon: Network, neo4jOnly: true },
  { id: 'console', label: 'Query Console', icon: Database },
  { id: 'workbench', label: 'Workbench', icon: Activity, hideNeo4j: true },
  { id: 'generate', label: 'Generate', icon: Play },
  { id: 'shell', label: 'Shell', icon: TerminalSquare },
]

function fmtCount(n?: number | null) {
  if (n == null) return '—'
  if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`
  if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`
  return String(n)
}

export function DataSourcesView({ focusEngine, onPulse }: Props) {
  const [active, setActive] = useState<SourceEngine>(focusEngine || 'postgres')
  const [subTab, setSubTab] = useState<SourceSubTab>('browser')
  const [health, setHealth] = useState<HealthMap>({})
  const [catalog, setCatalog] = useState<CatalogResponse | null>(null)
  const [catalogLoading, setCatalogLoading] = useState(false)
  const [selectedObject, setSelectedObject] = useState<CatalogObject | null>(null)
  const [sample, setSample] = useState<SampleResponse | null>(null)
  const [sampleLoading, setSampleLoading] = useState(false)
  const [page, setPage] = useState(1)
  const [pageSize, setPageSize] = useState(100)

  const meta = getSourceMeta(active)

  useEffect(() => {
    if (focusEngine) setActive(focusEngine)
  }, [focusEngine])

  useEffect(() => {
    if (active !== 'neo4j' && subTab === 'graph') setSubTab('browser')
  }, [active, subTab])

  const loadHealth = useCallback(async () => {
    try {
      const r = await fetch('/api/sql/health')
      if (r.ok) setHealth(await r.json())
    } catch { /* */ }
  }, [])

  const loadCatalog = useCallback(async (engine: SourceEngine) => {
    setCatalogLoading(true)
    setCatalog(null)
    setSelectedObject(null)
    setSample(null)
    try {
      const r = await fetch(`/api/sql/catalog/${engine}`)
      if (r.ok) {
        const j: CatalogResponse = await r.json()
        setCatalog(j)
        const first = j.objects?.find((o) => o.type === 'table' || o.type === 'collection' || o.type === 'node_label')
        if (first) setSelectedObject(first)
      }
    } catch { /* */ } finally {
      setCatalogLoading(false)
    }
  }, [])

  const loadSample = useCallback(async (engine: SourceEngine, obj: CatalogObject, pg = page, ps = pageSize) => {
    setSampleLoading(true)
    setSample(null)
    const offset = (pg - 1) * ps
    try {
      const r = await fetch(
        `/api/sql/sample/${engine}?object=${encodeURIComponent(obj.fqn)}&limit=${ps}&offset=${offset}`,
      )
      const j = await r.json()
      setSample(j)
    } catch {
      setSample({ ok: false, error: 'Sample API unavailable' })
    } finally {
      setSampleLoading(false)
    }
  }, [page, pageSize])

  useEffect(() => { loadHealth() }, [loadHealth])
  useEffect(() => {
    if (subTab === 'browser') loadCatalog(active)
  }, [active, subTab, loadCatalog])

  useEffect(() => {
    setPage(1)
  }, [selectedObject?.fqn, active])

  useEffect(() => {
    if (selectedObject && subTab === 'browser') loadSample(active, selectedObject, page, pageSize)
  }, [selectedObject, active, subTab, page, pageSize, loadSample])

  const refreshAll = () => {
    loadHealth()
    if (subTab === 'browser') {
      loadCatalog(active)
      if (selectedObject) loadSample(active, selectedObject, page, pageSize)
    } else if (subTab === 'graph' && active === 'neo4j') { /* Neo4jGraphView reloads itself */ }
    else if (selectedObject) loadSample(active, selectedObject, page, pageSize)
  }

  const visibleSubTabs = SUB_TABS.filter((t) => (!t.neo4jOnly || active === 'neo4j') && !(t.hideNeo4j && active === 'neo4j'))

  return (
    <div className="flex h-full min-h-0 flex-col gap-2 p-3">
      <header className="panel flex shrink-0 flex-wrap items-center justify-between gap-3 px-4 py-3">
        <div>
          <h1 className="flex items-center gap-2 text-base font-semibold text-foreground">
            <Server className="h-5 w-5 text-docker" />
            Data Sources UI
          </h1>
          <p className="text-[11px] text-foreground-muted">
            Browse, filter, edit &amp; query all source databases — edits on CDC sources flow to Live Changes
          </p>
        </div>
        <button type="button" onClick={refreshAll} className={cn('inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-[11px]', subTabIdle)}>
          <RefreshCw className="h-3.5 w-3.5" /> Refresh
        </button>
      </header>

      {/* Horizontal database selector */}
      <div className="panel shrink-0 px-3 py-2">
        <p className="mb-2 text-[9px] font-semibold uppercase tracking-widest text-foreground-muted">Source Databases</p>
        <div className="scroll-x-stable scrollbar-thin flex gap-2 pb-1">
          {SOURCE_CATALOG.map((src) => {
            const up = health[src.engine]?.ok
            const selected = active === src.engine
            const brand = dbBrandColor(src.engine)
            return (
              <button
                key={src.engine}
                type="button"
                onClick={() => setActive(src.engine)}
                className={cn(
                  'flex min-w-[148px] shrink-0 flex-col gap-1.5 rounded-lg border px-3 py-2.5 text-left transition-all',
                  selected
                    ? 'shadow-md'
                    : 'border-border/60 hover:border-border hover:bg-surface-overlay',
                )}
                style={selected ? { borderColor: brand, backgroundColor: `${brand}18`, boxShadow: `0 0 0 1px ${brand}40` } : undefined}
              >
                <div className="flex items-center justify-between gap-2">
                  <span className="flex items-center gap-2 text-[12px] font-semibold text-foreground">
                    <DbBrandIcon engine={src.engine} size={22} />
                    {src.label}
                  </span>
                  <span
                    className={cn(
                      'h-2 w-2 shrink-0 rounded-full',
                      up === true ? 'bg-emerald-400 shadow-[0_0_6px_rgba(52,211,153,0.6)]' : up === false ? 'bg-red-400' : 'bg-foreground-faint',
                    )}
                    title={up ? 'Online' : up === false ? 'Offline' : 'Unknown'}
                  />
                </div>
                <p className="line-clamp-2 text-[9px] leading-snug text-foreground-muted">{src.description}</p>
                <div className="flex flex-wrap gap-1">
                  <Badge variant="default">{src.host}:{src.port}</Badge>
                  {src.cdc && <Badge variant="accent">CDC</Badge>}
                </div>
              </button>
            )
          })}
        </div>
      </div>

      {/* Main panel — full width */}
      <div className="panel flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
        <div
          className="flex shrink-0 flex-wrap items-center justify-between gap-2 border-b border-border px-4 py-2.5"
          style={{ backgroundColor: `${dbBrandColor(active)}12` }}
        >
          <div>
            <h2 className="flex items-center gap-2 text-sm font-semibold text-foreground">
              <DbBrandIcon engine={active} size={18} />
              {meta.label}
              {catalog?.version && (
                <span className="font-mono text-[10px] font-normal text-foreground-muted">v{catalog.version.split(' ')[0]?.slice(0, 20)}</span>
              )}
            </h2>
            <p className="font-mono text-[10px] text-foreground-muted">
              {meta.host}:{meta.port} · {meta.database} · container {meta.container}
            </p>
          </div>
          <div className="flex flex-wrap gap-1">
            {visibleSubTabs.map(({ id, label, icon: Icon }) => (
              <button
                key={id}
                type="button"
                onClick={() => setSubTab(id)}
                className={cn('inline-flex items-center gap-1 rounded-md px-2.5 py-1 text-[10px] font-medium', subTab === id ? subTabActive : subTabIdle)}
              >
                <Icon className="h-3 w-3" /> {label}
              </button>
            ))}
          </div>
        </div>

        <div className="flex min-h-0 flex-1 flex-col overflow-hidden">
          {subTab === 'browser' && (
            <div className="flex h-full min-h-0 flex-1 overflow-hidden">
              <div className="flex w-[260px] shrink-0 flex-col border-r border-border/60">
                <div className="flex shrink-0 items-center justify-between border-b border-border/60 px-3 py-2">
                  <span className="text-[10px] font-semibold uppercase tracking-wider text-foreground-muted">Objects</span>
                  {catalogLoading && <Loader2 className="h-3 w-3 animate-spin text-foreground-muted" />}
                </div>
                <div className="scrollbar-thin min-h-0 flex-1 overflow-y-auto p-1.5">
                  {catalog?.objects?.map((obj) => (
                    <button
                      key={obj.fqn}
                      type="button"
                      onClick={() => setSelectedObject(obj)}
                      className={cn(
                        'mb-0.5 flex w-full items-center gap-1.5 rounded px-2 py-1.5 text-left text-[10px] transition-colors',
                        selectedObject?.fqn === obj.fqn ? subTabActive : 'hover:bg-surface-overlay',
                      )}
                    >
                      {obj.type === 'node_label' ? (
                        <Activity className="h-3 w-3 shrink-0" style={{ color: dbBrandColor('neo4j') }} />
                      ) : (
                        <Table2 className="h-3 w-3 shrink-0 text-foreground-muted" />
                      )}
                      <div className="min-w-0 flex-1">
                        <p className="truncate font-medium text-foreground">{obj.name}</p>
                        <p className="truncate font-mono text-[8px] text-foreground-muted">{obj.schema}{obj.type === 'relationship' ? ' · rel' : ''}</p>
                      </div>
                      <span className="shrink-0 font-mono text-[9px] text-foreground-muted">{fmtCount(obj.row_count)}</span>
                      <ChevronRight className="h-3 w-3 shrink-0 text-foreground-muted" />
                    </button>
                  ))}
                  {!catalogLoading && !catalog?.objects?.length && (
                    <p className="p-4 text-center text-[10px] text-foreground-muted">No objects found</p>
                  )}
                </div>
              </div>

              <div className="flex h-full min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
                <div className="flex shrink-0 items-center border-b border-border/60 px-3 py-2">
                  <span className="text-[10px] font-semibold text-foreground">
                    {selectedObject ? (
                      <>Data: <span className="font-mono text-docker">{selectedObject.fqn}</span></>
                    ) : 'Select an object'}
                  </span>
                </div>
                <DataBrowserGrid
                  engine={active}
                  objectFqn={selectedObject?.fqn || ''}
                  sample={selectedObject ? sample : null}
                  loading={sampleLoading}
                  page={page}
                  pageSize={pageSize}
                  onPageChange={setPage}
                  onPageSizeChange={(ps) => { setPageSize(ps); setPage(1) }}
                  onReload={() => selectedObject && loadSample(active, selectedObject, page, pageSize)}
                />
              </div>
            </div>
          )}

          {subTab === 'graph' && active === 'neo4j' && <Neo4jGraphView />}

          {subTab === 'console' && <SqlWorkbench engine={active} />}

          {subTab === 'workbench' && (
            <div className="flex min-h-0 flex-1 overflow-hidden">
              <LakehouseWorkbench lockedCatalog={ENGINE_CATALOG[active]} />
            </div>
          )}

          {subTab === 'generate' && onPulse && (
            <DataGenPanel embedded focusSource={active} onPulse={onPulse} />
          )}

          {subTab === 'shell' && <DbShell initialCommand={meta.shellCommand} />}
        </div>
      </div>
    </div>
  )
}
