import { useState, useMemo, memo } from 'react';
import {
  Brain,
  User,
  Library,
  History,
  Cpu,
  Globe,
  Star,
  Package,
  RefreshCw,
  X,
  ChevronDown,
  ChevronRight,
  Plus,
  Pencil,
  Trash2,
  Check,
} from 'lucide-react';
import type { MemorySummary, Command } from '../../types/protocol';

/* ── types ────────────────────────────────────────────── */

interface MemoryPanelProps {
  memories: MemorySummary[];
  onRefresh: () => void;
  onClose?: () => void;
  onCreateMemory: (ns: string, key: string, content: string) => Command;
  onUpdateMemory: (id: string, content: string) => Command;
  onDeleteMemory: (id: string) => Command;
  sendCommand: (cmd: Command) => void;
}

interface NamespaceConfig {
  label: string;
  icon: typeof Brain;
  accent: string;
  accentBorder: string;
}

const NS: Record<string, NamespaceConfig> = {
  user: {
    label: '用户记忆',
    icon: User,
    accent: 'text-[var(--accent-cyan)]',
    accentBorder: 'border-[var(--accent-cyan)]/40',
  },
  semantic: {
    label: '语义记忆',
    icon: Library,
    accent: 'text-[var(--accent-amber)]',
    accentBorder: 'border-[var(--accent-amber)]/40',
  },
  episodic: {
    label: '情景记忆',
    icon: History,
    accent: 'text-[var(--accent-purple)]',
    accentBorder: 'border-[var(--accent-purple)]/40',
  },
  skill: {
    label: '技能记忆',
    icon: Cpu,
    accent: 'text-[var(--accent-green)]',
    accentBorder: 'border-[var(--accent-green)]/40',
  },
  environment: {
    label: '环境记忆',
    icon: Globe,
    accent: 'text-[var(--accent-blue)]',
    accentBorder: 'border-[var(--accent-blue)]/40',
  },
  reflection: {
    label: '反思记忆',
    icon: Star,
    accent: 'text-[rgb(242,90,90)]',
    accentBorder: 'border-[rgb(242,90,90)]/40',
  },
  other: {
    label: '其他',
    icon: Package,
    accent: 'text-[var(--text-muted)]',
    accentBorder: 'border-[var(--border-color)]',
  },
};

function cfg(ns: string): NamespaceConfig {
  return (
    NS[ns] ?? {
      label: ns,
      icon: Package,
      accent: 'text-[var(--text-secondary)]',
      accentBorder: 'border-[var(--border-color)]',
    }
  );
}

function fmtKey(k: string) {
  return k.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
}

const NS_OPTIONS = Object.entries(NS);

/* ── Memory card with edit/delete ──────────────────────── */

function MemoryCard({
  memory,
  config,
  onUpdate,
  onDelete,
}: {
  memory: MemorySummary;
  config: NamespaceConfig;
  onUpdate: (id: string, content: string) => void;
  onDelete: (id: string) => void;
}) {
  const [editing, setEditing] = useState(false);
  const [editContent, setEditContent] = useState(memory.content);
  const [confirmDelete, setConfirmDelete] = useState(false);

  const handleSave = () => {
    if (editContent.trim() && editContent !== memory.content) {
      onUpdate(memory.id, editContent.trim());
    }
    setEditing(false);
  };

  const handleDelete = () => {
    if (confirmDelete) {
      onDelete(memory.id);
    } else {
      setConfirmDelete(true);
      setTimeout(() => setConfirmDelete(false), 3000);
    }
  };

  return (
    <div
      className={`group rounded-lg bg-[var(--overlay-hover)] border-l-2 ${config.accentBorder} border border-[var(--border-color)] overflow-hidden transition-all duration-200 hover:border-[var(--border-accent)]`}
    >
      <div className="px-3 py-2.5">
        {/* header row */}
        <div className="flex items-center justify-between mb-0.5">
          <span
            className={`text-[10px] font-mono uppercase tracking-wider ${config.accent} opacity-60`}
          >
            {fmtKey(memory.memory_key)}
          </span>
          {/* action buttons — visible on hover */}
          <div className="flex items-center gap-0.5 opacity-0 group-hover:opacity-100 transition-opacity">
            <button
              onClick={() => {
                setEditing(!editing);
                setEditContent(memory.content);
              }}
              className={`p-1 rounded hover:bg-[var(--overlay-subtle)] ${editing ? 'text-[var(--accent-cyan)]' : 'text-[var(--text-muted)]'} hover:text-[var(--accent-cyan)] transition-colors`}
              title="编辑"
            >
              <Pencil className="h-3 w-3" />
            </button>
            <button
              onClick={handleDelete}
              className={`p-1 rounded hover:bg-[rgb(242,90,90)]/10 ${confirmDelete ? 'text-[rgb(242,90,90)]' : 'text-[var(--text-muted)]'} hover:text-[rgb(242,90,90)] transition-colors`}
              title={confirmDelete ? '再次点击确认删除' : '删除'}
            >
              <Trash2 className="h-3 w-3" />
            </button>
          </div>
        </div>

        {/* content */}
        {editing ? (
          <div className="flex gap-1.5 mt-1">
            <textarea
              value={editContent}
              onChange={(e) => setEditContent(e.target.value)}
              className="flex-1 text-sm bg-[var(--bg-tertiary)] border border-[var(--border-color)] rounded-lg px-2 py-1.5 text-[var(--text-primary)] resize-none focus:outline-none focus:border-[var(--accent-cyan)] min-h-[120px]"
              autoFocus
              onKeyDown={(e) => {
                if (e.key === 'Enter' && !e.shiftKey) {
                  e.preventDefault();
                  handleSave();
                }
              }}
            />
            <button
              onClick={handleSave}
              className="shrink-0 p-1.5 rounded-lg bg-[var(--accent-cyan)]/10 text-[var(--accent-cyan)] hover:bg-[var(--accent-cyan)]/20 transition-colors"
              title="保存"
            >
              <Check className="h-3.5 w-3.5" />
            </button>
          </div>
        ) : (
          <p className="text-sm text-[var(--text-secondary)] leading-relaxed">{memory.content}</p>
        )}
      </div>
    </div>
  );
}

/* ── Add memory form ───────────────────────────────────── */

function AddMemoryForm({
  onAdd,
  onCancel,
}: {
  onAdd: (ns: string, key: string, content: string) => void;
  onCancel: () => void;
}) {
  const [ns, setNs] = useState('user');
  const [key, setKey] = useState('');
  const [content, setContent] = useState('');

  const handleSubmit = () => {
    if (!key.trim() || !content.trim()) return;
    onAdd(ns, key.trim(), content.trim());
  };

  return (
    <div className="rounded-xl border border-[var(--border-accent)] bg-[var(--bg-tertiary)]/80 p-3 space-y-2.5 animate-fade-in">
      <div className="flex gap-2">
        <select
          value={ns}
          onChange={(e) => setNs(e.target.value)}
          className="text-xs bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-lg px-2 py-1.5 text-[var(--text-primary)]"
        >
          {NS_OPTIONS.map(([k, v]) => (
            <option key={k} value={k}>
              {v.label}
            </option>
          ))}
        </select>
        <input
          value={key}
          onChange={(e) => setKey(e.target.value)}
          placeholder="键名 (如 work_preference)"
          className="flex-1 text-xs bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-lg px-2 py-1.5 text-[var(--text-primary)] placeholder:text-[var(--text-muted)]"
        />
      </div>
      <textarea
        value={content}
        onChange={(e) => setContent(e.target.value)}
        placeholder="内容..."
        className="w-full text-sm bg-[var(--bg-secondary)] border border-[var(--border-color)] rounded-lg px-2.5 py-2 text-[var(--text-primary)] placeholder:text-[var(--text-muted)] resize-none min-h-[120px]"
        autoFocus
        onKeyDown={(e) => {
          if (e.key === 'Enter' && !e.shiftKey) {
            e.preventDefault();
            handleSubmit();
          }
        }}
      />
      <div className="flex justify-end gap-1.5">
        <button
          onClick={onCancel}
          className="px-3 py-1 rounded-lg text-xs text-[var(--text-muted)] hover:bg-[var(--overlay-hover)] transition-colors"
        >
          取消
        </button>
        <button
          onClick={handleSubmit}
          disabled={!key.trim() || !content.trim()}
          className="px-3 py-1 rounded-lg text-xs bg-[var(--accent-cyan)]/10 text-[var(--accent-cyan)] hover:bg-[var(--accent-cyan)]/20 transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
        >
          创建
        </button>
      </div>
    </div>
  );
}

/* ── Section header ────────────────────────────────────── */

function SectionHeader({
  config,
  count,
  isCollapsed,
  onClick,
}: {
  config: NamespaceConfig;
  count: number;
  isCollapsed: boolean;
  onClick: () => void;
}) {
  const Icon = config.icon;
  return (
    <button
      onClick={onClick}
      className="sticky top-0 z-10 group flex items-center gap-2 w-full py-1.5 rounded-lg transition-colors hover:bg-[var(--overlay-hover)] bg-[var(--bg-secondary)]/90 backdrop-blur-sm -mx-3 px-3"
    >
      {isCollapsed ? (
        <ChevronRight className="h-3 w-3 text-[var(--text-muted)]" />
      ) : (
        <ChevronDown className="h-3 w-3 text-[var(--text-muted)]" />
      )}
      <div
        className={`flex items-center justify-center w-5 h-5 rounded-md bg-[var(--overlay-hover)] ${config.accent}`}
      >
        <Icon className="h-3 w-3" />
      </div>
      <span className="text-xs font-semibold text-[var(--text-primary)] tracking-tight">
        {config.label}
      </span>
      <span className="text-[10px] text-[var(--text-muted)] font-mono tabular-nums ml-auto">
        {count}
      </span>
    </button>
  );
}

/* ── main component ────────────────────────────────────── */

// memo：props 全部稳定（memories 仅在刷新时换引用、回调均 useCallback），
// 主视图流式期间 App 每帧重渲染时跳过面板重渲染与分组/排序重算。
export const MemoryPanel = memo(function MemoryPanel({
  memories,
  onRefresh,
  onClose,
  onCreateMemory,
  onUpdateMemory,
  onDeleteMemory,
  sendCommand,
}: MemoryPanelProps) {
  const [collapsed, setCollapsed] = useState<Set<string>>(() => {
    try {
      const s = localStorage.getItem('picobot-memory-collapsed');
      return s ? new Set(JSON.parse(s)) : new Set();
    } catch (_) {
      return new Set();
    }
  });
  const [showAddForm, setShowAddForm] = useState(false);

  const toggle = (ns: string) => {
    setCollapsed((prev) => {
      const next = new Set(prev);
      if (next.has(ns)) {
        next.delete(ns);
      } else {
        next.add(ns);
      }
      localStorage.setItem('picobot-memory-collapsed', JSON.stringify([...next]));
      return next;
    });
  };

  // memories 引用未变时跳过分组/排序重算（流式期间 App 每帧重渲染）
  const { grouped, sorted } = useMemo(() => {
    const grouped = new Map<string, MemorySummary[]>();
    for (const m of memories) {
      const l = grouped.get(m.namespace) || [];
      l.push(m);
      grouped.set(m.namespace, l);
    }

    const order = ['user', 'semantic', 'episodic', 'skill', 'environment', 'reflection', 'other'];
    const sorted = Array.from(grouped.keys()).sort((a, b) => {
      const ai = order.indexOf(a);
      const bi = order.indexOf(b);
      if (ai !== -1 && bi !== -1) return ai - bi;
      if (ai !== -1) return -1;
      if (bi !== -1) return 1;
      return a.localeCompare(b);
    });
    return { grouped, sorted };
  }, [memories]);

  const handleCreate = (ns: string, key: string, content: string) => {
    sendCommand(onCreateMemory(ns, key, content));
    setShowAddForm(false);
  };
  const handleUpdate = (id: string, content: string) => {
    sendCommand(onUpdateMemory(id, content));
  };
  const handleDelete = (id: string) => {
    sendCommand(onDeleteMemory(id));
  };

  return (
    <div className="flex h-full flex-col">
      {/* title bar */}
      <div className="shrink-0 border-b border-[var(--border-color)] px-4 py-3 flex items-center gap-2.5">
        <div className="flex items-center justify-center w-6 h-6 rounded-lg bg-[var(--accent-cyan)]/10">
          <Brain className="h-3.5 w-3.5 text-[var(--accent-cyan)]" />
        </div>
        <span className="text-sm font-bold text-[var(--text-primary)] tracking-tight">记忆</span>
        {memories.length > 0 && (
          <span className="text-[11px] font-mono text-[var(--text-muted)] tabular-nums ml-0.5">
            {memories.length}
          </span>
        )}
        <div className="ml-auto flex items-center gap-0.5">
          <button
            onClick={() => setShowAddForm(!showAddForm)}
            className={`p-1.5 rounded-lg transition-colors ${showAddForm ? 'bg-[var(--accent-cyan)]/10 text-[var(--accent-cyan)]' : 'text-[var(--text-muted)] hover:bg-[var(--overlay-hover)] hover:text-[var(--accent-cyan)]'}`}
            title="新增记忆"
          >
            <Plus className="h-3.5 w-3.5" />
          </button>
          <button
            onClick={onRefresh}
            className="p-1.5 rounded-lg hover:bg-[var(--overlay-hover)] text-[var(--text-muted)] hover:text-[var(--accent-cyan)] transition-colors"
            title="刷新"
          >
            <RefreshCw className="h-3.5 w-3.5" />
          </button>
          {onClose && (
            <button
              onClick={onClose}
              className="p-1.5 rounded-lg hover:bg-[var(--overlay-hover)] text-[var(--text-muted)] hover:text-[var(--text-secondary)] transition-colors"
              title="收起"
            >
              <X className="h-3.5 w-3.5" />
            </button>
          )}
        </div>
      </div>

      {/* add form */}
      {showAddForm && (
        <div className="px-3 pt-2">
          <AddMemoryForm onAdd={handleCreate} onCancel={() => setShowAddForm(false)} />
        </div>
      )}

      {/* empty */}
      {memories.length === 0 && !showAddForm && (
        <div className="flex flex-1 items-center justify-center p-8">
          <div className="text-center select-none">
            <div className="relative inline-block mb-5">
              <div className="absolute inset-0 rounded-full bg-[var(--accent-cyan)]/10 blur-xl animate-pulse" />
              <Brain className="relative h-12 w-12 text-[var(--accent-cyan)]/25" />
            </div>
            <p className="text-sm text-[var(--text-muted)] leading-relaxed">
              PicoBot 会在对话中
              <br />
              自动学习并记录关于你的信息
            </p>
          </div>
        </div>
      )}

      {/* list */}
      {memories.length > 0 && (
        <div className="flex-1 overflow-y-auto px-3 pt-0 pb-2 space-y-3">
          {sorted.map((ns) => {
            const c = cfg(ns);
            const items = grouped.get(ns)!;
            const closed = collapsed.has(ns);
            return (
              <div key={ns}>
                <SectionHeader
                  config={c}
                  count={items.length}
                  isCollapsed={closed}
                  onClick={() => toggle(ns)}
                />
                {!closed && (
                  <div className="mt-1.5 space-y-1.5">
                    {items.map((m) => (
                      <MemoryCard
                        key={m.id}
                        memory={m}
                        config={c}
                        onUpdate={handleUpdate}
                        onDelete={handleDelete}
                      />
                    ))}
                  </div>
                )}
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
});
