/**
 * DbBrowserPanel — read-only SQLite inspector for the active project.
 *
 * Left pane: table list with row counts; right pane: column definitions
 * and a paginated row table.  Mounted as a tab inside PreviewPanel.
 *
 * Schema and row fetches both go through /api/projects/<id>/db/... which
 * opens the DB read-only.  Schema auto-refreshes on tab focus + every
 * REFRESH_INTERVAL_MS so writes from the running backend show up without
 * a manual reload.
 */

import { useEffect, useMemo, useState } from 'react'
import useAppStore from '../store/appStore'

const REFRESH_INTERVAL_MS = 6_000

export default function DbBrowserPanel() {
  const projectId = useAppStore((s) => s.project.id)

  const [schema, setSchema]       = useState(null)
  const [activeTbl, setActiveTbl] = useState(null)
  const [rows, setRows]           = useState(null)
  const [offset, setOffset]       = useState(0)
  const [error, setError]         = useState(null)
  const [loading, setLoading]     = useState(false)

  const PAGE = 100

  // Load schema (and re-poll while the panel is mounted so backend writes
  // become visible without explicit user action).
  useEffect(() => {
    if (!projectId) return
    let cancelled = false

    async function loadSchema() {
      try {
        const r = await fetch(`/api/projects/${projectId}/db/schema`)
        if (!r.ok) {
          if (!cancelled) {
            const err = await r.json().catch(() => ({}))
            setError(err.detail || `HTTP ${r.status}`)
            setSchema(null)
          }
          return
        }
        const data = await r.json()
        if (cancelled) return
        setError(null)
        setSchema(data)
      } catch (e) {
        if (!cancelled) setError(String(e.message || e))
      }
    }

    loadSchema()
    const id = setInterval(loadSchema, REFRESH_INTERVAL_MS)
    return () => { cancelled = true; clearInterval(id) }
  }, [projectId])

  // Auto-select the first table whenever the list refreshes and we don't
  // already have a still-valid selection.
  useEffect(() => {
    if (!schema?.tables?.length) {
      setActiveTbl(null)
      return
    }
    const names = schema.tables.map((t) => t.name)
    if (!activeTbl || !names.includes(activeTbl)) {
      setActiveTbl(schema.tables[0].name)
      setOffset(0)
    }
  }, [schema, activeTbl])

  // Load rows for the active table whenever the selection or page moves.
  useEffect(() => {
    if (!projectId || !activeTbl) { setRows(null); return }
    let cancelled = false
    setLoading(true)

    async function loadRows() {
      try {
        const url = `/api/projects/${projectId}/db/rows`
                  + `?table=${encodeURIComponent(activeTbl)}`
                  + `&limit=${PAGE}&offset=${offset}`
        const r = await fetch(url)
        if (!r.ok) {
          const err = await r.json().catch(() => ({}))
          if (!cancelled) { setRows(null); setError(err.detail || `HTTP ${r.status}`) }
          return
        }
        const data = await r.json()
        if (cancelled) return
        setRows(data)
        setError(null)
      } catch (e) {
        if (!cancelled) setError(String(e.message || e))
      } finally {
        if (!cancelled) setLoading(false)
      }
    }
    loadRows()
    return () => { cancelled = true }
  }, [projectId, activeTbl, offset])

  const tables = schema?.tables ?? []
  const activeMeta = useMemo(
    () => tables.find((t) => t.name === activeTbl),
    [tables, activeTbl],
  )

  if (!projectId) {
    return <EmptyState label="Open a project to browse its database." />
  }
  if (schema && !schema.exists) {
    return <EmptyState label={`No database yet — run the project to create ${schema.db_path}.`} />
  }
  if (error && !schema) {
    return <EmptyState label={error} tone="error" />
  }

  return (
    <div style={{ display: 'flex', height: '100%', background: 'var(--bg)' }}>
      {/* Tables sidebar */}
      <div
        style={{
          width:        180,
          borderRight:  '1px solid var(--border)',
          background:   'var(--surface)',
          overflow:     'auto',
          flexShrink:   0,
        }}
      >
        <div
          style={{
            padding:       '8px 10px 6px',
            fontSize:      10,
            color:         'var(--text-faint)',
            textTransform: 'uppercase',
            letterSpacing: '0.08em',
          }}
        >
          Tables ({tables.length})
        </div>
        {tables.length === 0 && (
          <div style={{ padding: '0 10px', fontSize: 11, color: 'var(--text-faint)' }}>
            No tables yet. Create one in schema.sql (or via Prisma migrate).
          </div>
        )}
        {tables.map((t) => {
          const active = t.name === activeTbl
          return (
            <button
              key={t.name}
              onClick={() => { setActiveTbl(t.name); setOffset(0) }}
              style={{
                display:    'flex',
                alignItems: 'center',
                justifyContent: 'space-between',
                width:      '100%',
                padding:    '6px 10px',
                border:     'none',
                background: active ? 'var(--surface-2)' : 'transparent',
                color:      active ? 'var(--text)' : 'var(--text-dim)',
                cursor:     'pointer',
                textAlign:  'left',
                fontFamily: 'ui-monospace, "JetBrains Mono", monospace',
                fontSize:   12,
                borderLeft: active ? '2px solid var(--accent)' : '2px solid transparent',
              }}
            >
              <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                {t.name}
              </span>
              <span style={{ color: 'var(--text-faint)', fontSize: 10 }}>
                {t.row_count}
              </span>
            </button>
          )
        })}
      </div>

      {/* Right: schema + rows */}
      <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 }}>
        {activeMeta && (
          <div
            style={{
              padding:      '8px 12px',
              borderBottom: '1px solid var(--border)',
              background:   'var(--surface)',
              display:      'flex',
              gap:          12,
              alignItems:   'center',
              flexWrap:     'wrap',
              fontSize:     11,
            }}
          >
            <span
              style={{
                fontFamily: 'ui-monospace, "JetBrains Mono", monospace',
                color:      'var(--text)',
                fontWeight: 600,
              }}
            >
              {activeMeta.name}
            </span>
            <span style={{ color: 'var(--text-faint)' }}>
              {activeMeta.columns.length} cols · {activeMeta.row_count} rows
            </span>
            <span style={{ flex: 1 }} />
            <Pager
              offset={offset}
              limit={PAGE}
              total={activeMeta.row_count}
              onChange={setOffset}
            />
          </div>
        )}

        <div style={{ flex: 1, minHeight: 0, overflow: 'auto' }}>
          {loading && !rows && (
            <div style={{ padding: 16, fontSize: 12, color: 'var(--text-faint)' }}>Loading…</div>
          )}
          {rows && <RowTable rows={rows} columns={activeMeta?.columns ?? []} />}
        </div>
      </div>
    </div>
  )
}

function RowTable({ rows, columns }) {
  if (!rows.rows.length) {
    return (
      <div style={{ padding: 16, fontSize: 12, color: 'var(--text-faint)' }}>
        Empty table — INSERTs from the running app show up here on the next refresh.
      </div>
    )
  }
  const colMeta = Object.fromEntries(columns.map((c) => [c.name, c]))
  return (
    <table
      style={{
        borderCollapse: 'separate',
        borderSpacing:  0,
        width:          '100%',
        fontSize:       11.5,
        fontFamily:     'ui-monospace, "JetBrains Mono", monospace',
        color:          'var(--text)',
      }}
    >
      <thead>
        <tr>
          {rows.columns.map((c) => (
            <th
              key={c}
              style={{
                textAlign:    'left',
                padding:      '6px 10px',
                background:   'var(--surface)',
                borderBottom: '1px solid var(--border-2)',
                fontWeight:   600,
                color:        'var(--text-dim)',
                whiteSpace:   'nowrap',
                position:     'sticky',
                top:          0,
              }}
            >
              {c}
              {colMeta[c]?.pk && (
                <span style={{ marginLeft: 5, color: 'var(--accent)', fontSize: 9 }} title="primary key">★</span>
              )}
              <div style={{ fontWeight: 400, fontSize: 9.5, color: 'var(--text-faint)' }}>
                {colMeta[c]?.type || ''}
              </div>
            </th>
          ))}
        </tr>
      </thead>
      <tbody>
        {rows.rows.map((row, i) => (
          <tr key={i}>
            {row.map((cell, j) => (
              <td
                key={j}
                style={{
                  padding:      '4px 10px',
                  borderBottom: '1px solid var(--border)',
                  verticalAlign:'top',
                  maxWidth:     320,
                  overflow:     'hidden',
                  textOverflow: 'ellipsis',
                  whiteSpace:   'nowrap',
                  color:        cell == null ? 'var(--text-faint)' : 'var(--text)',
                }}
                title={cell == null ? 'NULL' : String(cell)}
              >
                {cell == null ? 'NULL' : String(cell)}
              </td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  )
}

function Pager({ offset, limit, total, onChange }) {
  const last = Math.max(0, Math.floor((total - 1) / limit) * limit)
  const cur  = Math.floor(offset / limit) + 1
  const max  = Math.max(1, Math.floor((total - 1) / limit) + 1)
  return (
    <div style={{ display: 'flex', gap: 4, alignItems: 'center', color: 'var(--text-faint)' }}>
      <PagerBtn disabled={offset === 0} onClick={() => onChange(0)}>«</PagerBtn>
      <PagerBtn disabled={offset === 0} onClick={() => onChange(Math.max(0, offset - limit))}>‹</PagerBtn>
      <span style={{ fontSize: 10.5, padding: '0 4px' }}>{cur}/{max}</span>
      <PagerBtn disabled={offset >= last} onClick={() => onChange(Math.min(last, offset + limit))}>›</PagerBtn>
      <PagerBtn disabled={offset >= last} onClick={() => onChange(last)}>»</PagerBtn>
    </div>
  )
}

function PagerBtn({ disabled, onClick, children }) {
  return (
    <button
      disabled={disabled}
      onClick={onClick}
      style={{
        width: 22, height: 22,
        borderRadius: 4,
        border: '1px solid var(--border-2)',
        background: 'var(--surface-2)',
        color: disabled ? 'var(--text-faint)' : 'var(--text-dim)',
        cursor: disabled ? 'default' : 'pointer',
        fontSize: 11,
      }}
    >{children}</button>
  )
}

function EmptyState({ label, tone }) {
  return (
    <div
      style={{
        height: '100%',
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center',
        justifyContent: 'center',
        gap: 8,
        color: tone === 'error' ? 'var(--danger)' : 'var(--text-faint)',
        fontSize: 12.5,
        padding: 24,
        textAlign: 'center',
        background: 'var(--bg)',
      }}
    >
      <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1" style={{ opacity: 0.4 }}>
        <ellipse cx="12" cy="5" rx="9" ry="3" />
        <path d="M3 5v14c0 1.7 4 3 9 3s9-1.3 9-3V5" />
        <path d="M3 12c0 1.7 4 3 9 3s9-1.3 9-3" />
      </svg>
      {label}
    </div>
  )
}
