import { useState, useEffect, useRef } from "react";
import { Plus, ChevronDown, ChevronRight, Star, Trash2 } from "lucide-react";
import { COLORS, FONT, STATE_COLOR } from "./theme";
import type { Group, WorkspaceView, SurfaceState } from "./layoutTypes";
import type { DaemonHealth } from "./socketBridge";
import { setWorkspaceMeta } from "./socketBridge";

function fmtUptime(startedMs: number): string {
  const s = Math.max(0, Math.floor((Date.now() - startedMs) / 1000));
  if (s < 60) return `${s}s`;
  if (s < 3600) return `${Math.floor(s / 60)}m`;
  if (s < 86400) return `${Math.floor(s / 3600)}h ${Math.floor((s % 3600) / 60)}m`;
  return `${Math.floor(s / 86400)}d ${Math.floor((s % 86400) / 3600)}h`;
}

function aggregate(w: WorkspaceView): SurfaceState | "stopped" {
  const order: SurfaceState[] = ["error", "wait", "work", "done", "idle"];
  const running = Object.values(w.surfaces).filter((s) => s.running);
  if (running.length === 0) return "stopped";
  for (const st of order) {
    if (running.some((s) => s.state === st)) return st;
  }
  return "idle";
}

interface DropAt { section: string; index: number }

export function Sidebar({
  railMode, groups, workspaces, activeId, onSelect, onNew, onDelete, health, connected,
}: {
  railMode: boolean;
  groups: Group[];
  workspaces: WorkspaceView[];
  activeId: string | null;
  onSelect: (id: string) => void;
  onNew: () => void;
  onDelete: (w: WorkspaceView) => void;
  health: DaemonHealth | null;
  connected: boolean;
}) {
  const [collapsed, setCollapsed] = useState<Record<string, boolean>>({});
  const [hovered, setHovered] = useState<string | null>(null);
  const [drag, setDrag] = useState<{ id: string; section: string } | null>(null);
  const [dropAt, setDropAt] = useState<DropAt | null>(null);
  const [editing, setEditing] = useState<{ id: string; draft: string } | null>(null);
  const dragRef = useRef<{ id: string; section: string } | null>(null);
  const dropRef = useRef<DropAt | null>(null);
  const [, setTick] = useState(0);
  dragRef.current = drag;
  dropRef.current = dropAt;

  useEffect(() => {
    const t = setInterval(() => setTick((n) => n + 1), 30000);
    return () => clearInterval(t);
  }, []);

  const pinned = workspaces.filter((w) => w.pinned).sort((a, b) => a.order - b.order);
  const byGroup = (gid: string | null) =>
    workspaces.filter((w) => !w.pinned && (w.group_id ?? null) === gid).sort((a, b) => a.order - b.order);
  const ungrouped = byGroup(null);

  const togglePin = (w: WorkspaceView) => { void setWorkspaceMeta(w.id, { pinned: !w.pinned }); };

  const commitRename = () => {
    setEditing((cur) => {
      if (cur) {
        const name = cur.draft.trim();
        const w = workspaces.find((x) => x.id === cur.id);
        if (name && w && name !== w.name) void setWorkspaceMeta(cur.id, { name });
      }
      return null;
    });
  };

  // Persist a new ordering for one section by reassigning sequential `order`
  // values (per-section; values never compared across sections).
  const commitReorder = (items: WorkspaceView[], fromId: string, toIndex: number) => {
    const fromIndex = items.findIndex((w) => w.id === fromId);
    if (fromIndex < 0) return;
    const next = [...items];
    const [moved] = next.splice(fromIndex, 1);
    next.splice(Math.min(toIndex, next.length), 0, moved);
    next.forEach((w, i) => { if (w.order !== i) void setWorkspaceMeta(w.id, { order: i }); });
  };

  const startDrag = (w: WorkspaceView, section: string, items: WorkspaceView[], e: React.MouseEvent) => {
    if (e.button !== 0) return;
    const startX = e.clientX, startY = e.clientY;
    let active = false;
    const prevUserSelect = document.body.style.userSelect;
    const move = (ev: MouseEvent) => {
      if (!active) {
        if (Math.abs(ev.clientX - startX) + Math.abs(ev.clientY - startY) < 5) return;
        active = true;
        document.body.style.userSelect = "none";
        setDrag({ id: w.id, section });
      }
      const el = (document.elementFromPoint(ev.clientX, ev.clientY) as HTMLElement | null)?.closest("[data-ws-id]") as HTMLElement | null;
      if (!el || el.getAttribute("data-ws-section") !== section) { setDropAt(null); return; }
      const idx = Number(el.getAttribute("data-ws-index"));
      const r = el.getBoundingClientRect();
      const after = ev.clientY > r.top + r.height / 2;
      setDropAt({ section, index: after ? idx + 1 : idx });
    };
    const up = () => {
      window.removeEventListener("mousemove", move);
      window.removeEventListener("mouseup", up);
      document.body.style.userSelect = prevUserSelect;
      const d = dropRef.current;
      const dr = dragRef.current;
      setDrag(null); setDropAt(null);
      if (active && d && dr && d.section === section) commitReorder(items, dr.id, d.index);
    };
    window.addEventListener("mousemove", move);
    window.addEventListener("mouseup", up);
  };

  const row = (w: WorkspaceView, section: string, items: WorkspaceView[], index: number) => {
    const isActive = w.id === activeId;
    const showLine = dropAt && dropAt.section === section && dropAt.index === index;
    const showLineEnd = dropAt && dropAt.section === section && dropAt.index === items.length && index === items.length - 1;
    return (
      <div key={w.id}>
        {showLine && <div style={{ height: 2, background: COLORS.accent, borderRadius: 2, margin: "1px 0" }} />}
        <div
          data-ws-id={w.id} data-ws-section={section} data-ws-index={index}
          onClick={() => onSelect(w.id)}
          onMouseDown={(e) => startDrag(w, section, items, e)}
          onMouseEnter={() => setHovered(w.id)}
          onMouseLeave={() => setHovered((h) => (h === w.id ? null : h))}
          style={{
            display: "flex", alignItems: "center", gap: 8, height: 34, padding: "0 8px", borderRadius: 6,
            cursor: drag?.id === w.id ? "grabbing" : "pointer",
            opacity: drag?.id === w.id ? 0.5 : 1,
            background: isActive ? COLORS.bgElevated : "transparent", fontFamily: FONT.ui, fontSize: 13,
            color: isActive ? COLORS.textPrimary : COLORS.textSecondary,
          }}>
          <span style={{ width: 10, height: 10, borderRadius: "50%", border: `2px solid ${STATE_COLOR[aggregate(w)]}`, boxSizing: "border-box", flex: "0 0 10px" }} />
          {editing?.id === w.id ? (
            <input
              autoFocus
              value={editing.draft}
              onFocus={(e) => e.target.select()}
              onMouseDown={(e) => e.stopPropagation()}
              onClick={(e) => e.stopPropagation()}
              onChange={(e) => setEditing({ id: w.id, draft: e.target.value })}
              onBlur={commitRename}
              onKeyDown={(e) => {
                e.stopPropagation();
                if (e.key === "Enter") { e.preventDefault(); commitRename(); }
                else if (e.key === "Escape") { e.preventDefault(); setEditing(null); }
              }}
              style={{ flex: 1, minWidth: 0, background: COLORS.bgApp, color: COLORS.textPrimary, border: `1px solid ${COLORS.accent}`, borderRadius: 4, padding: "2px 6px", fontFamily: FONT.ui, fontSize: 13, outline: "none" }}
            />
          ) : (
            <span
              onDoubleClick={(e) => { e.stopPropagation(); setEditing({ id: w.id, draft: w.name }); }}
              title="Двойной клик — переименовать"
              style={{ flex: 1, fontWeight: isActive ? 600 : 400, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
              {w.name}
            </span>
          )}
          {(hovered === w.id || w.pinned) && (
            <Star size={14} fill={w.pinned ? COLORS.stWait : "none"} color={w.pinned ? COLORS.stWait : COLORS.textMuted}
              style={{ cursor: "pointer", flex: "0 0 14px" }}
              onMouseDown={(e) => e.stopPropagation()}
              onClick={(e) => { e.stopPropagation(); togglePin(w); }} />
          )}
          {hovered === w.id && (
            <Trash2 size={14} color={COLORS.textMuted}
              style={{ cursor: "pointer", flex: "0 0 14px" }}
              onMouseDown={(e) => e.stopPropagation()}
              onClick={(e) => { e.stopPropagation(); onDelete(w); }} />
          )}
          {w.unread && <span style={{ width: 7, height: 7, borderRadius: "50%", background: COLORS.accent, flex: "0 0 7px" }} />}
          <span style={{ display: "flex", alignItems: "center", justifyContent: "center", height: 18, minWidth: 18, padding: "0 6px", borderRadius: 9, background: COLORS.bgApp, fontFamily: FONT.mono, fontSize: 11, color: COLORS.textSecondary }}>
            {Object.keys(w.surfaces).length}
          </span>
        </div>
        {showLineEnd && <div style={{ height: 2, background: COLORS.accent, borderRadius: 2, margin: "1px 0" }} />}
      </div>
    );
  };

  const section = (key: string, items: WorkspaceView[]) => items.map((w, i) => row(w, key, items, i));

  // Collapsed: a narrow rail of status rings so terminal activity stays visible.
  if (railMode) {
    const rail = [
      ...pinned,
      ...groups.slice().sort((a, b) => a.order - b.order).flatMap((g) => byGroup(g.id)),
      ...ungrouped,
    ];
    return (
      <div style={{ position: "relative", zIndex: 20, display: "flex", flexDirection: "column", alignItems: "center", width: 48, flex: "0 0 48px", background: COLORS.sidebarGlass, backdropFilter: COLORS.panelBlur, WebkitBackdropFilter: COLORS.panelBlur, height: "100%", padding: "10px 0", boxSizing: "border-box", borderRight: `1px solid ${COLORS.borderSubtle}`, gap: 8 }}>
        <button onClick={onNew} title="New workspace"
          style={{ display: "flex", alignItems: "center", justifyContent: "center", width: 30, height: 30, borderRadius: 8, background: COLORS.bgElevated, border: `1px solid ${COLORS.borderStrong}`, color: COLORS.textPrimary, cursor: "pointer" }}>
          <Plus size={15} />
        </button>
        <div style={{ flex: 1, overflowY: "auto", display: "flex", flexDirection: "column", alignItems: "center", gap: 6, minHeight: 0 }}>
          {rail.map((w) => {
            const isActive = w.id === activeId;
            return (
              <button key={w.id} onClick={() => onSelect(w.id)} title={w.name}
                style={{ position: "relative", display: "flex", alignItems: "center", justifyContent: "center", width: 32, height: 32, borderRadius: 8, cursor: "pointer", background: isActive ? COLORS.bgElevated : "transparent", border: `1px solid ${isActive ? COLORS.borderStrong : "transparent"}` }}>
                <span style={{ width: 12, height: 12, borderRadius: "50%", border: `2px solid ${STATE_COLOR[aggregate(w)]}`, boxSizing: "border-box" }} />
                {w.unread && <span style={{ position: "absolute", top: 3, right: 3, width: 7, height: 7, borderRadius: "50%", background: COLORS.accent }} />}
              </button>
            );
          })}
        </div>
        <span title={connected ? "spaceshd · live" : "spaceshd · offline"}
          style={{ width: 8, height: 8, borderRadius: "50%", background: connected ? COLORS.stDone : COLORS.textMuted, flex: "0 0 8px" }} />
      </div>
    );
  }

  return (
    <div style={{ display: "flex", flexDirection: "column", width: 248, flex: "0 0 248px", background: COLORS.sidebarGlass, backdropFilter: COLORS.panelBlur, WebkitBackdropFilter: COLORS.panelBlur, height: "100%", padding: 14, boxSizing: "border-box" }}>
      <button onClick={onNew}
        style={{
          display: "flex", alignItems: "center", justifyContent: "center", gap: 8, width: "100%", height: 34, marginBottom: 16,
          background: COLORS.bgElevated, color: COLORS.textPrimary, border: `1px solid ${COLORS.borderStrong}`, borderRadius: 7,
          fontFamily: FONT.ui, fontSize: 13, fontWeight: 600,
        }}>
        <Plus size={15} />
        New workspace
        <span style={{ fontFamily: FONT.mono, fontSize: 11, color: COLORS.textMuted }}>⌘N</span>
      </button>

      <div style={{ flex: 1, overflowY: "auto", display: "flex", flexDirection: "column", gap: 2, minHeight: 0 }}>
        {pinned.length > 0 && (
          <div style={{ marginBottom: 8 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 7, height: 24, padding: "0 4px" }}>
              <Star size={12} fill={COLORS.stWait} color={COLORS.stWait} />
              <span style={{ fontFamily: FONT.ui, fontSize: 11, fontWeight: 700, letterSpacing: 0.5, color: COLORS.textSecondary }}>FAVORITES</span>
            </div>
            {section("fav", pinned)}
          </div>
        )}
        {groups.sort((a, b) => a.order - b.order).map((g) => {
          const open = !collapsed[g.id];
          const items = byGroup(g.id);
          return (
            <div key={g.id} style={{ marginBottom: 8 }}>
              <div onClick={() => setCollapsed((c) => ({ ...c, [g.id]: open }))}
                style={{ display: "flex", alignItems: "center", gap: 7, height: 24, padding: "0 4px", cursor: "pointer" }}>
                {open ? <ChevronDown size={13} color={COLORS.textMuted} /> : <ChevronRight size={13} color={COLORS.textMuted} />}
                <span style={{ width: 8, height: 8, borderRadius: 2, background: g.color }} />
                <span style={{ fontFamily: FONT.ui, fontSize: 11, fontWeight: 700, letterSpacing: 0.5, color: COLORS.textSecondary }}>{g.name.toUpperCase()}</span>
              </div>
              {open && section(`g:${g.id}`, items)}
            </div>
          );
        })}
        {ungrouped.length > 0 && <div style={{ marginTop: 4, display: "flex", flexDirection: "column", gap: 2 }}>{section("ungrouped", ungrouped)}</div>}
      </div>

      <div title={health ? `spaceshd v${health.version} · pid ${health.pid}` : "daemon offline"}
        style={{ display: "flex", alignItems: "center", gap: 8, height: 30, marginTop: 10, padding: "0 6px", borderRadius: 6, background: COLORS.bgPanel }}>
        <span style={{ width: 7, height: 7, borderRadius: "50%", background: connected ? COLORS.stDone : COLORS.textMuted, flex: "0 0 7px" }} />
        <span style={{ fontFamily: FONT.mono, fontSize: 11, color: COLORS.textSecondary }}>{connected ? "spaceshd · live" : "spaceshd · offline"}</span>
        <span style={{ flex: 1 }} />
        <span style={{ fontFamily: FONT.mono, fontSize: 11, color: COLORS.textMuted }}>{health ? fmtUptime(health.started_at_ms) : ""}</span>
      </div>
    </div>
  );
}
