import { useMemo, useState } from 'react';
import { ArrowUp, ArrowDown, ArrowUpDown, X, Search, ChevronRight, ChevronDown, Lock, Unlock } from 'lucide-react';
import Button from '../../ui/Button';

const TYPES = ['concept', 'role', 'process'];
const RELEVANCE = ['core', 'standard', 'peripheral', 'exclude'];

const SORTABLE = ['label', 'type', 'learning_relevance', 'theme', 'complexity_weight', 'difficulty', 'relations'];

const GROUP_OPTIONS = [
  { value: 'none',                label: 'No grouping' },
  { value: 'type',                label: 'Type' },
  { value: 'learning_relevance',  label: 'Relevance' },
  { value: 'theme',               label: 'Theme' },
  { value: 'difficulty',          label: 'Difficulty' },
];

const RELEVANCE_RANK = { core: 0, standard: 1, peripheral: 2, exclude: 3 };
const DIFFICULTY_RANK = { beginner: 0, intermediate: 1, advanced: 2 };

function compareValues(a, b, key) {
  if (key === 'learning_relevance') {
    return (RELEVANCE_RANK[a] ?? 99) - (RELEVANCE_RANK[b] ?? 99);
  }
  if (key === 'difficulty') {
    return (DIFFICULTY_RANK[a] ?? 99) - (DIFFICULTY_RANK[b] ?? 99);
  }
  if (typeof a === 'number' && typeof b === 'number') return a - b;
  return String(a ?? '').localeCompare(String(b ?? ''), undefined, { sensitivity: 'base' });
}

function SortIcon({ active, dir }) {
  if (!active) return <ArrowUpDown size={11} className="text-fg-muted/60 inline-block ml-1" />;
  return dir === 'asc'
    ? <ArrowUp size={11} className="text-teal inline-block ml-1" />
    : <ArrowDown size={11} className="text-teal inline-block ml-1" />;
}

/**
 * Table view of the knowledge graph.
 *
 * Supports sort (per column), grouping (per key), free-text label filter,
 * multi-row selection, and bulk-change of type / learning_relevance / lock.
 *
 * Persistence is delegated to onBulkUpdate(ids, patch). The parent (KnowledgeGraph)
 * provides this from useGraphData.bulkUpdateTopics.
 */
export default function GraphTable({
  topics,
  relations,
  onBulkUpdate,
  onSelectNode,
}) {
  const [sortKey, setSortKey] = useState('label');
  const [sortDir, setSortDir] = useState('asc');
  const [groupBy, setGroupBy] = useState('none');
  const [query, setQuery] = useState('');
  const [selectedIds, setSelectedIds] = useState(() => new Set());
  const [collapsed, setCollapsed] = useState(() => new Set());

  // Bulk-action form state
  const [bulkType, setBulkType] = useState('');
  const [bulkRelevance, setBulkRelevance] = useState('');
  const [bulkLockOnRelevance, setBulkLockOnRelevance] = useState(true);
  const [isApplying, setIsApplying] = useState(false);
  const [feedback, setFeedback] = useState(null);

  // Pre-compute relation counts per topic so the column is cheap to render.
  const relationCount = useMemo(() => {
    const counts = new Map();
    for (const r of relations) {
      counts.set(r.source, (counts.get(r.source) || 0) + 1);
      counts.set(r.target, (counts.get(r.target) || 0) + 1);
    }
    return counts;
  }, [relations]);

  // Filter + sort
  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    const rows = topics
      .map(t => ({
        ...t,
        learning_relevance: t.learning_relevance || 'standard',
        type: t.type || 'concept',
        difficulty: t.difficulty || 'intermediate',
        complexity_weight: t.complexity_weight ?? 3,
        theme: t.theme || '',
        relations: relationCount.get(t.id) || 0,
      }))
      .filter(t => !q || t.label?.toLowerCase().includes(q) || t.description?.toLowerCase().includes(q));

    const sorted = [...rows].sort((a, b) => {
      const cmp = compareValues(a[sortKey], b[sortKey], sortKey);
      return sortDir === 'asc' ? cmp : -cmp;
    });
    return sorted;
  }, [topics, relationCount, query, sortKey, sortDir]);

  // Group rows (flat array if groupBy === 'none')
  const groups = useMemo(() => {
    if (groupBy === 'none') return [{ key: '__all__', label: null, rows: filtered }];
    const map = new Map();
    for (const t of filtered) {
      const k = t[groupBy] || '—';
      if (!map.has(k)) map.set(k, []);
      map.get(k).push(t);
    }
    return [...map.entries()]
      .sort(([a], [b]) => compareValues(a, b, groupBy))
      .map(([key, rows]) => ({ key, label: String(key), rows }));
  }, [filtered, groupBy]);

  // ── Selection helpers ─────────────────────────────────────────────────────

  const allVisibleIds = useMemo(() => filtered.map(t => t.id), [filtered]);
  const visibleSelected = useMemo(
    () => allVisibleIds.filter(id => selectedIds.has(id)).length,
    [allVisibleIds, selectedIds],
  );
  const allVisibleChecked = visibleSelected === allVisibleIds.length && allVisibleIds.length > 0;
  const someVisibleChecked = visibleSelected > 0 && !allVisibleChecked;

  const toggleOne = (id) => {
    setSelectedIds(prev => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });
  };
  const toggleAllVisible = () => {
    setSelectedIds(prev => {
      const next = new Set(prev);
      if (allVisibleChecked) {
        for (const id of allVisibleIds) next.delete(id);
      } else {
        for (const id of allVisibleIds) next.add(id);
      }
      return next;
    });
  };
  const toggleGroup = (groupRows) => {
    setSelectedIds(prev => {
      const next = new Set(prev);
      const ids = groupRows.map(r => r.id);
      const allOn = ids.every(id => next.has(id));
      for (const id of ids) (allOn ? next.delete(id) : next.add(id));
      return next;
    });
  };
  const clearSelection = () => setSelectedIds(new Set());

  // ── Sorting ───────────────────────────────────────────────────────────────

  const onSort = (key) => {
    if (!SORTABLE.includes(key)) return;
    if (sortKey === key) {
      setSortDir(d => (d === 'asc' ? 'desc' : 'asc'));
    } else {
      setSortKey(key);
      setSortDir('asc');
    }
  };

  // ── Bulk actions ──────────────────────────────────────────────────────────

  const runBulk = async (patch, label) => {
    if (selectedIds.size === 0) return;
    setIsApplying(true);
    setFeedback(null);
    try {
      const n = await onBulkUpdate([...selectedIds], patch);
      setFeedback(`${label} — ${n} topic${n === 1 ? '' : 's'} updated.`);
    } catch (e) {
      setFeedback(`Failed: ${e.message || 'unknown error'}`);
    } finally {
      setIsApplying(false);
    }
  };

  const applyBulkType = () => {
    if (!bulkType) return;
    runBulk({ type: bulkType }, `Type → ${bulkType}`);
  };
  const applyBulkRelevance = () => {
    if (!bulkRelevance) return;
    const patch = { learning_relevance: bulkRelevance };
    if (bulkLockOnRelevance) patch.relevance_locked = true;
    runBulk(patch, `Relevance → ${bulkRelevance}${bulkLockOnRelevance ? ' (locked)' : ''}`);
  };
  const applyLock = (locked) => {
    runBulk({ relevance_locked: locked }, locked ? 'Locked relevance' : 'Unlocked relevance');
  };

  // ── Render ────────────────────────────────────────────────────────────────

  const totalSel = selectedIds.size;
  const isCollapsed = (key) => collapsed.has(key);
  const toggleCollapse = (key) => {
    setCollapsed(prev => {
      const next = new Set(prev);
      next.has(key) ? next.delete(key) : next.add(key);
      return next;
    });
  };

  return (
    <div className="h-full flex flex-col bg-paper">
      {/* Toolbar */}
      <div className="flex flex-wrap items-center gap-3 p-3 border-b border-bg-warm bg-bg">
        <div className="relative">
          <Search size={14} className="absolute left-2 top-1/2 -translate-y-1/2 text-fg-muted pointer-events-none" />
          <input
            type="text"
            value={query}
            onChange={e => setQuery(e.target.value)}
            placeholder="Filter by label or description…"
            className="pl-7 pr-3 py-1.5 text-sm border border-bg-warm rounded-[var(--r-sm)] bg-paper w-64"
          />
        </div>
        <label className="text-xs text-fg-muted flex items-center gap-1.5">
          Group by
          <select
            value={groupBy}
            onChange={e => setGroupBy(e.target.value)}
            className="border border-bg-warm rounded-[var(--r-sm)] px-2 py-1 text-xs bg-paper"
          >
            {GROUP_OPTIONS.map(o => (
              <option key={o.value} value={o.value}>{o.label}</option>
            ))}
          </select>
        </label>
        <span className="text-xs text-fg-muted ml-auto">
          {filtered.length} of {topics.length} topics
          {totalSel > 0 && <> · <span className="text-teal font-medium">{totalSel} selected</span></>}
        </span>
      </div>

      {/* Bulk action bar */}
      {totalSel > 0 && (
        <div className="flex flex-wrap items-center gap-2 p-3 border-b border-bg-warm bg-teal/5">
          <span className="text-xs font-medium text-teal mr-1">Bulk:</span>

          {/* Type */}
          <div className="flex items-center gap-1">
            <select
              value={bulkType}
              onChange={e => setBulkType(e.target.value)}
              className="border border-bg-warm rounded-[var(--r-sm)] px-2 py-1 text-xs bg-paper"
              disabled={isApplying}
            >
              <option value="">— set type —</option>
              {TYPES.map(t => <option key={t} value={t}>{t}</option>)}
            </select>
            <Button
              onClick={applyBulkType}
              disabled={!bulkType || isApplying}
              className="px-2 py-1 text-xs"
            >Apply</Button>
          </div>

          {/* Relevance */}
          <div className="flex items-center gap-1">
            <select
              value={bulkRelevance}
              onChange={e => setBulkRelevance(e.target.value)}
              className="border border-bg-warm rounded-[var(--r-sm)] px-2 py-1 text-xs bg-paper"
              disabled={isApplying}
            >
              <option value="">— set relevance —</option>
              {RELEVANCE.map(r => <option key={r} value={r}>{r}</option>)}
            </select>
            <label className="flex items-center gap-1 text-xs text-fg-muted cursor-pointer">
              <input
                type="checkbox"
                checked={bulkLockOnRelevance}
                onChange={e => setBulkLockOnRelevance(e.target.checked)}
                className="rounded bg-bg-warm border-transparent focus:ring-0 text-teal"
              />
              lock
            </label>
            <Button
              onClick={applyBulkRelevance}
              disabled={!bulkRelevance || isApplying}
              className="px-2 py-1 text-xs"
            >Apply</Button>
          </div>

          {/* Lock toggles */}
          <button
            onClick={() => applyLock(true)}
            disabled={isApplying}
            className="flex items-center gap-1 px-2 py-1 text-xs border border-bg-warm rounded-[var(--r-sm)] bg-paper hover:bg-bg-warm/50 disabled:opacity-40"
            title="Lock relevance for selected topics"
          >
            <Lock size={11} /> Lock
          </button>
          <button
            onClick={() => applyLock(false)}
            disabled={isApplying}
            className="flex items-center gap-1 px-2 py-1 text-xs border border-bg-warm rounded-[var(--r-sm)] bg-paper hover:bg-bg-warm/50 disabled:opacity-40"
            title="Unlock relevance for selected topics"
          >
            <Unlock size={11} /> Unlock
          </button>

          <button
            onClick={clearSelection}
            className="ml-auto flex items-center gap-1 px-2 py-1 text-xs text-fg-muted hover:text-fg"
          >
            <X size={12} /> Clear
          </button>

          {feedback && (
            <span className="basis-full text-xs text-fg-muted">{feedback}</span>
          )}
        </div>
      )}

      {/* Table */}
      <div className="flex-1 overflow-auto">
        <table className="w-full text-sm">
          <thead className="bg-bg sticky top-0 z-10">
            <tr className="text-left border-b border-bg-warm">
              <th className="px-3 py-2 w-8">
                <input
                  type="checkbox"
                  checked={allVisibleChecked}
                  ref={el => { if (el) el.indeterminate = someVisibleChecked; }}
                  onChange={toggleAllVisible}
                  className="rounded bg-bg-warm border-transparent focus:ring-0 text-teal"
                  title={allVisibleChecked ? 'Deselect all visible' : 'Select all visible'}
                />
              </th>
              {[
                ['label', 'Label'],
                ['type', 'Type'],
                ['learning_relevance', 'Relevance'],
                ['theme', 'Theme'],
                ['difficulty', 'Difficulty'],
                ['complexity_weight', 'Weight'],
                ['relations', 'Rel.'],
              ].map(([key, label]) => (
                <th
                  key={key}
                  onClick={() => onSort(key)}
                  className="px-3 py-2 text-xs uppercase tracking-wider text-fg-muted cursor-pointer select-none hover:text-teal"
                >
                  {label}<SortIcon active={sortKey === key} dir={sortDir} />
                </th>
              ))}
              <th className="px-3 py-2 text-xs uppercase tracking-wider text-fg-muted">Lock</th>
            </tr>
          </thead>

          <tbody>
            {groups.map(group => (
              <Group
                key={group.key}
                group={group}
                groupBy={groupBy}
                collapsed={isCollapsed(group.key)}
                onToggleCollapse={() => toggleCollapse(group.key)}
                onToggleGroup={() => toggleGroup(group.rows)}
                selectedIds={selectedIds}
                onToggleOne={toggleOne}
                onSelectNode={onSelectNode}
              />
            ))}
            {filtered.length === 0 && (
              <tr>
                <td colSpan={9} className="px-3 py-12 text-center text-fg-muted text-sm">
                  No topics match the current filter.
                </td>
              </tr>
            )}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function Group({
  group, groupBy, collapsed, onToggleCollapse, onToggleGroup,
  selectedIds, onToggleOne, onSelectNode,
}) {
  const groupHeader = groupBy !== 'none' && group.label != null;
  const groupSelectedCount = group.rows.filter(r => selectedIds.has(r.id)).length;
  const allGroupSelected = groupSelectedCount === group.rows.length && group.rows.length > 0;
  const someGroupSelected = groupSelectedCount > 0 && !allGroupSelected;

  return (
    <>
      {groupHeader && (
        <tr className="bg-bg-warm/40 border-b border-bg-warm">
          <td className="px-3 py-1.5 w-8">
            <input
              type="checkbox"
              checked={allGroupSelected}
              ref={el => { if (el) el.indeterminate = someGroupSelected; }}
              onChange={onToggleGroup}
              className="rounded bg-bg-warm border-transparent focus:ring-0 text-teal"
            />
          </td>
          <td colSpan={8} className="px-3 py-1.5 text-xs font-medium text-fg-muted">
            <button
              onClick={onToggleCollapse}
              className="inline-flex items-center gap-1 text-fg-muted hover:text-teal"
            >
              {collapsed ? <ChevronRight size={12} /> : <ChevronDown size={12} />}
              <span className="uppercase tracking-wider">{group.label}</span>
              <span className="text-fg-muted/70 normal-case">· {group.rows.length}</span>
            </button>
          </td>
        </tr>
      )}
      {!collapsed && group.rows.map(t => (
        <Row
          key={t.id}
          topic={t}
          checked={selectedIds.has(t.id)}
          onToggle={() => onToggleOne(t.id)}
          onSelectNode={onSelectNode}
        />
      ))}
    </>
  );
}

function Row({ topic, checked, onToggle, onSelectNode }) {
  return (
    <tr
      className={`border-b border-bg-warm/60 hover:bg-bg-warm/30 transition-colors ${checked ? 'bg-teal/5' : ''}`}
    >
      <td className="px-3 py-2 w-8">
        <input
          type="checkbox"
          checked={checked}
          onChange={onToggle}
          className="rounded bg-bg-warm border-transparent focus:ring-0 text-teal"
        />
      </td>
      <td className="px-3 py-2">
        <button
          onClick={() => onSelectNode?.(topic)}
          className="text-left hover:text-teal underline-offset-2 hover:underline"
          title={topic.description || ''}
        >
          {topic.label}
        </button>
      </td>
      <td className="px-3 py-2 font-mono text-xs">{topic.type}</td>
      <td className="px-3 py-2 font-mono text-xs">{topic.learning_relevance}</td>
      <td className="px-3 py-2 text-xs text-fg-muted">{topic.theme || '—'}</td>
      <td className="px-3 py-2 text-xs">{topic.difficulty}</td>
      <td className="px-3 py-2 text-xs text-center">{topic.complexity_weight}</td>
      <td className="px-3 py-2 text-xs text-center text-fg-muted">{topic.relations}</td>
      <td className="px-3 py-2 text-center">
        {topic.relevance_locked
          ? <Lock size={12} className="text-teal inline" />
          : <Unlock size={12} className="text-fg-muted/40 inline" />}
      </td>
    </tr>
  );
}
