/* global React, ReactDOM */
const { useState, useEffect, useRef } = React;

const CFG = window.TOK_CONFIG;
const sb = window.supabase.createClient(CFG.SUPABASE_URL, CFG.SUPABASE_KEY);

// ── konstante / stil ──────────────────────────────────────────
const PRIO = {
  visok: { label: "visok", rank: 3, cls: "bg-orange-50 text-orange-700 border-orange-200" },
  srednji: { label: "srednji", rank: 2, cls: "bg-amber-50 text-amber-700 border-amber-200" },
  nizak: { label: "nizak", rank: 1, cls: "bg-stone-100 text-stone-500 border-stone-200" },
};
const mono = { fontFamily: "'SF Mono','JetBrains Mono','Menlo',ui-monospace,monospace" };
const display = { fontFamily: "'Helvetica Neue',Helvetica,Arial,sans-serif", letterSpacing: "-0.03em" };

// ── helpers ───────────────────────────────────────────────────
function tint(hex, a) {
  const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex || "");
  if (!m) return "transparent";
  return `rgba(${parseInt(m[1],16)},${parseInt(m[2],16)},${parseInt(m[3],16)},${a})`;
}
function fmtDate(iso) {
  if (!iso) return null;
  const d = new Date(iso + "T00:00:00");
  if (isNaN(d)) return null;
  return d.toLocaleDateString("sr-RS", { day: "2-digit", month: "2-digit", year: "numeric" });
}
function daysUntil(iso) {
  if (!iso) return null;
  const d = new Date(iso + "T00:00:00"); const t = new Date(); t.setHours(0,0,0,0);
  return Math.round((d - t) / 86400000);
}
function ymd(d) { return d.getFullYear() + String(d.getMonth()+1).padStart(2,"0") + String(d.getDate()).padStart(2,"0"); }
function effectivePriority(task) {
  const d = daysUntil(task.dueDate);
  let byDate = d === null ? null : (d <= 3 ? "visok" : d <= 7 ? "srednji" : "nizak");
  const base = PRIO[task.basePriority] ? task.basePriority : "srednji";
  if (byDate === null) return base;
  return PRIO[byDate].rank >= PRIO[base].rank ? byDate : base;
}
function calLink(task) {
  if (!task.dueDate) return null;
  const start = new Date(task.dueDate + "T00:00:00"); start.setDate(start.getDate() - 1);
  const end = new Date(start); end.setDate(end.getDate() + 1);
  const text = encodeURIComponent("Podsetnik: " + task.title);
  const details = encodeURIComponent((task.description ? task.description + "\n\n" : "") + "Rok: " + fmtDate(task.dueDate) + " — podsetnik je dan ranije.");
  return "https://calendar.google.com/calendar/render?action=TEMPLATE&text=" + text + "&dates=" + ymd(start) + "/" + ymd(end) + "&details=" + details;
}

// ── mapiranje baza <-> aplikacija ─────────────────────────────
const taskFromDB = (r) => ({
  id: r.id, title: r.title, description: r.description || "",
  dueDate: r.due_date, basePriority: r.base_priority || "srednji",
  clientId: r.client_id, ownerId: r.owner_id, column: r.column_id,
  completedAt: r.completed_at ? new Date(r.completed_at).getTime() : null,
  archived: !!r.archived, archivedAt: r.archived_at ? new Date(r.archived_at).getTime() : null,
});
const taskToDB = (t) => ({
  title: t.title, description: t.description || "", due_date: t.dueDate || null,
  base_priority: t.basePriority || "srednji", client_id: t.clientId || null,
  owner_id: t.ownerId || null, column_id: t.column || "todo",
  completed_at: t.completedAt ? new Date(t.completedAt).toISOString() : null,
  archived: !!t.archived, archived_at: t.archivedAt ? new Date(t.archivedAt).toISOString() : null,
});
function patchToDB(p) {
  const d = {};
  if ("title" in p) d.title = p.title;
  if ("description" in p) d.description = p.description;
  if ("dueDate" in p) d.due_date = p.dueDate;
  if ("basePriority" in p) d.base_priority = p.basePriority;
  if ("clientId" in p) d.client_id = p.clientId;
  if ("ownerId" in p) d.owner_id = p.ownerId;
  if ("column" in p) d.column_id = p.column;
  if ("completedAt" in p) d.completed_at = p.completedAt == null ? null : new Date(p.completedAt).toISOString();
  if ("archived" in p) d.archived = p.archived;
  if ("archivedAt" in p) d.archived_at = p.archivedAt == null ? null : new Date(p.archivedAt).toISOString();
  return d;
}
const settingsFromDB = (r) => ({
  clients: r.clients, columns: r.columns, owners: r.owners,
  doneColumnId: r.done_column_id, archiveAfterDays: r.archive_after_days,
});
const settingsToDB = (s) => ({
  clients: s.clients, columns: s.columns, owners: s.owners,
  done_column_id: s.doneColumnId, archive_after_days: s.archiveAfterDays,
});

// ── AI razvrstavanje preko serverske funkcije ─────────────────
async function parseTasks(text, today, clients, owners) {
  const { data: { session } } = await sb.auth.getSession();
  const res = await fetch("/api/parse", {
    method: "POST",
    headers: { "Content-Type": "application/json", Authorization: "Bearer " + (session ? session.access_token : "") },
    body: JSON.stringify({ text, today, clients: clients.map((c) => c.name), owners: owners.map((o) => o.name) }),
  });
  const out = await res.json();
  if (!res.ok || out.error) throw new Error(out.error || "parse failed");
  const arr = JSON.parse(out.result);
  return arr.map((t) => {
    const mc = clients.find((c) => c.name.toLowerCase() === String(t.client || "").toLowerCase());
    const mo = owners.find((o) => o.name.toLowerCase() === String(t.owner || "").toLowerCase());
    return {
      title: (t.title || "Bez naziva").trim(), description: (t.description || "").trim(),
      dueDate: t.dueDate || null, basePriority: PRIO[t.priority] ? t.priority : "srednji",
      clientId: mc ? mc.id : null, ownerId: mo ? mo.id : null, column: "todo",
    };
  });
}

// ── Card ──────────────────────────────────────────────────────
function Card({ task, columns, client, owner, onMove, onDelete, onDrag, onCycleOwner, onArchive }) {
  const [confirmDel, setConfirmDel] = useState(false);
  const cal = calLink(task);
  const idx = columns.findIndex((c) => c.id === task.column);
  const prio = effectivePriority(task);
  const d = daysUntil(task.dueDate);
  const overdue = d !== null && d < 0 && !onArchive;
  return (
    <div draggable onDragStart={(e) => onDrag(e, task.id)}
      className="group border border-stone-200 rounded-lg shadow-sm hover:shadow-md hover:border-stone-300 transition-all cursor-grab active:cursor-grabbing overflow-hidden"
      style={{ borderLeft: `3px solid ${client ? client.color : "#d6d3d1"}`, background: owner ? tint(owner.color, 0.13) : "#ffffff" }}>
      <div className="p-3.5">
        <div className="flex items-center gap-2 mb-1.5">
          <button onClick={() => onCycleOwner(task.id)}
            className="flex items-center gap-1.5 text-[11px] font-medium px-1.5 py-0.5 rounded-full hover:opacity-70 transition"
            style={owner ? { color: owner.color } : { color: "#a8a29e" }} title="Tapni da promeniš čije je">
            <span className="w-2 h-2 rounded-full" style={{ background: owner ? owner.color : "#d6d3d1" }} />
            {owner ? owner.name : "—"}
          </button>
        </div>
        <h3 className="text-[15px] font-semibold text-stone-900 leading-snug">{task.title}</h3>
        {task.description && <p className="text-[13px] text-stone-500 mt-1.5 leading-relaxed">{task.description}</p>}
        <div className="flex flex-wrap items-center gap-1.5 mt-3" style={mono}>
          {client && <span className="text-[11px] px-2 py-0.5 rounded-full font-medium" style={{ background: tint(client.color, 0.12), color: client.color }}>{client.name}</span>}
          <span className={"text-[11px] px-2 py-0.5 rounded border " + PRIO[prio].cls}>{PRIO[prio].label}</span>
          {task.dueDate && <span className={"text-[11px] px-2 py-0.5 rounded border " + (overdue ? "border-orange-300 bg-orange-50 text-orange-700" : "border-stone-200 bg-white/70 text-stone-600")}>{overdue ? "kasni " : "rok "}{fmtDate(task.dueDate)}</span>}
          {task.dueDate && <span className="text-[11px] px-2 py-0.5 rounded border border-indigo-100 bg-indigo-50 text-indigo-600">−1d</span>}
        </div>
        <div className="flex items-center justify-between mt-3 pt-2.5 border-t border-stone-200/60">
          <div className="flex items-center gap-1">
            <button onClick={() => onMove(task.id, -1)} disabled={idx <= 0} className="w-6 h-6 rounded text-stone-400 hover:bg-black/5 hover:text-stone-700 disabled:opacity-25 transition text-sm">‹</button>
            <button onClick={() => onMove(task.id, 1)} disabled={idx >= columns.length - 1} className="w-6 h-6 rounded text-stone-400 hover:bg-black/5 hover:text-stone-700 disabled:opacity-25 transition text-sm">›</button>
          </div>
          <div className="flex items-center gap-3">
            {cal ? <a href={cal} target="_blank" rel="noopener noreferrer" className="text-[12px] font-medium text-indigo-600 hover:text-indigo-800 hover:underline">U kalendar →</a> : <span className="text-[11px] text-stone-300" style={mono}>bez roka</span>}
            {onArchive && !confirmDel && <button onClick={() => onArchive(task.id)} className="text-[12px] font-medium text-stone-500 hover:text-stone-800">Arhiviraj</button>}
            {confirmDel ? (
              <span className="flex items-center gap-2">
                <button onClick={() => onDelete(task.id)} className="text-[12px] font-semibold text-orange-600 hover:text-orange-700">Obriši?</button>
                <button onClick={() => setConfirmDel(false)} className="text-[12px] text-stone-400 hover:text-stone-600">Ne</button>
              </span>
            ) : (
              <button onClick={() => setConfirmDel(true)} className="text-[12px] font-medium text-stone-400 hover:text-orange-600">Obriši</button>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

// ── color/name editor ─────────────────────────────────────────
function ColorList({ items, onUpdate, onAdd, onDel, addLabel }) {
  return (
    <>
      <div className="space-y-2">
        {items.map((it) => (
          <div key={it.id} className="flex items-center gap-2 bg-white border border-stone-200 rounded-lg p-2">
            <input type="color" value={it.color} onChange={(e) => onUpdate(it.id, { color: e.target.value })} className="w-8 h-8 rounded cursor-pointer border-0 bg-transparent p-0" />
            <input value={it.name} onChange={(e) => onUpdate(it.id, { name: e.target.value })} className="flex-1 text-sm text-stone-800 outline-none bg-transparent" />
            <button onClick={() => onDel(it.id)} className="text-stone-300 hover:text-orange-500 px-1">×</button>
          </div>
        ))}
      </div>
      <button onClick={onAdd} className="mt-2 text-sm text-indigo-600 hover:text-indigo-800 font-medium">{addLabel}</button>
    </>
  );
}

// ── Settings ──────────────────────────────────────────────────
function Settings({ settings, setSettings, onClose }) {
  const upd = (key) => (id, patch) => setSettings((s) => ({ ...s, [key]: s[key].map((c) => (c.id === id ? { ...c, ...patch } : c)) }));
  const add = (key, base) => () => setSettings((s) => ({ ...s, [key]: [...s[key], { id: "x" + Date.now().toString(36), ...base }] }));
  const del = (key) => (id) => setSettings((s) => ({ ...s, [key]: s[key].filter((c) => c.id !== id) }));
  const moveCol = (id, dir) => setSettings((s) => {
    const i = s.columns.findIndex((c) => c.id === id), ni = i + dir;
    if (ni < 0 || ni >= s.columns.length) return s;
    const cols = [...s.columns]; [cols[i], cols[ni]] = [cols[ni], cols[i]]; return { ...s, columns: cols };
  });
  const delCol = (id) => setSettings((s) => (s.columns.length <= 1 ? s : { ...s, columns: s.columns.filter((c) => c.id !== id) }));
  return (
    <div className="fixed inset-0 z-50 flex justify-end bg-black/30" onClick={onClose}>
      <div className="w-full max-w-md h-full bg-stone-50 overflow-y-auto shadow-2xl" onClick={(e) => e.stopPropagation()}>
        <div className="sticky top-0 bg-stone-50 border-b border-stone-200 px-5 py-4 flex items-center justify-between">
          <h2 className="text-lg font-bold text-stone-900" style={display}>Podešavanja</h2>
          <button onClick={onClose} className="text-stone-400 hover:text-stone-700 text-xl">×</button>
        </div>
        <div className="p-5 space-y-8">
          <section>
            <h3 className="text-[13px] font-semibold uppercase tracking-wide text-stone-500 mb-1">Osobe — čije je</h3>
            <p className="text-[12px] text-stone-400 mb-3">Boja postaje pozadina kartice. Na kartici tapni obeleživač da promeniš.</p>
            <ColorList items={settings.owners} onUpdate={upd("owners")} onAdd={add("owners", { name: "Nova osoba", color: "#64748b" })} onDel={del("owners")} addLabel="+ Dodaj osobu" />
          </section>
          <section>
            <h3 className="text-[13px] font-semibold uppercase tracking-wide text-stone-500 mb-3">Klijenti</h3>
            <ColorList items={settings.clients} onUpdate={upd("clients")} onAdd={add("clients", { name: "Novi klijent", color: "#64748b" })} onDel={del("clients")} addLabel="+ Dodaj klijenta" />
          </section>
          <section>
            <h3 className="text-[13px] font-semibold uppercase tracking-wide text-stone-500 mb-3">Kolone table</h3>
            <div className="space-y-2">
              {settings.columns.map((c, i) => (
                <div key={c.id} className="flex items-center gap-2 bg-white border border-stone-200 rounded-lg p-2">
                  <div className="flex flex-col">
                    <button onClick={() => moveCol(c.id, -1)} disabled={i === 0} className="text-stone-400 hover:text-stone-700 disabled:opacity-20 text-xs leading-none">▲</button>
                    <button onClick={() => moveCol(c.id, 1)} disabled={i === settings.columns.length - 1} className="text-stone-400 hover:text-stone-700 disabled:opacity-20 text-xs leading-none">▼</button>
                  </div>
                  <input value={c.label} onChange={(e) => upd("columns")(c.id, { label: e.target.value })} className="flex-1 text-sm text-stone-800 outline-none bg-transparent" />
                  <button onClick={() => delCol(c.id)} disabled={settings.columns.length <= 1} className="text-stone-300 hover:text-orange-500 disabled:opacity-20 px-1">×</button>
                </div>
              ))}
            </div>
            <button onClick={add("columns", { label: "Nova kolona" })} className="mt-2 text-sm text-indigo-600 hover:text-indigo-800 font-medium">+ Dodaj kolonu</button>
          </section>
          <section>
            <h3 className="text-[13px] font-semibold uppercase tracking-wide text-stone-500 mb-3">Završeno i arhiva</h3>
            <label className="block text-[13px] text-stone-600 mb-1">Kolona koja znači „završeno"</label>
            <select value={settings.doneColumnId} onChange={(e) => setSettings((s) => ({ ...s, doneColumnId: e.target.value }))} className="w-full text-sm bg-white border border-stone-200 rounded-lg p-2 text-stone-800 outline-none">
              {settings.columns.map((c) => <option key={c.id} value={c.id}>{c.label}</option>)}
            </select>
            <label className="block text-[13px] text-stone-600 mb-1 mt-3">Arhiviraj posle (dana)</label>
            <input type="number" min={1} max={365} value={settings.archiveAfterDays} onChange={(e) => setSettings((s) => ({ ...s, archiveAfterDays: Math.max(1, parseInt(e.target.value) || 7) }))} className="w-24 text-sm bg-white border border-stone-200 rounded-lg p-2 text-stone-800 outline-none" />
          </section>
        </div>
      </div>
    </div>
  );
}

// ── Arhiva ────────────────────────────────────────────────────
function ArchiveModal({ items, settings, onRestore, onDelete, onClose }) {
  const [confirmId, setConfirmId] = useState(null);
  const cBy = (id) => settings.clients.find((c) => c.id === id) || null;
  const oBy = (id) => settings.owners.find((o) => o.id === id) || null;
  const sorted = [...items].sort((a, b) => (b.archivedAt || 0) - (a.archivedAt || 0));
  return (
    <div className="fixed inset-0 z-50 flex justify-end bg-black/30" onClick={onClose}>
      <div className="w-full max-w-md h-full bg-stone-50 overflow-y-auto shadow-2xl" onClick={(e) => e.stopPropagation()}>
        <div className="sticky top-0 bg-stone-50 border-b border-stone-200 px-5 py-4 flex items-center justify-between">
          <h2 className="text-lg font-bold text-stone-900" style={display}>Arhiva <span className="text-stone-400 font-normal" style={mono}>{sorted.length}</span></h2>
          <button onClick={onClose} className="text-stone-400 hover:text-stone-700 text-xl">×</button>
        </div>
        <div className="p-5 space-y-2.5">
          {sorted.length === 0 && <p className="text-sm text-stone-400 text-center py-10">Arhiva je prazna.</p>}
          {sorted.map((t) => {
            const c = cBy(t.clientId), o = oBy(t.ownerId);
            return (
              <div key={t.id} className="bg-white border border-stone-200 rounded-lg p-3" style={{ borderLeft: `3px solid ${c ? c.color : "#d6d3d1"}` }}>
                <h3 className="text-[14px] font-semibold text-stone-800 leading-snug">{t.title}</h3>
                <div className="flex flex-wrap items-center gap-1.5 mt-1.5" style={mono}>
                  {o && <span className="text-[11px] px-2 py-0.5 rounded-full" style={{ background: tint(o.color, 0.13), color: o.color }}>{o.name}</span>}
                  {c && <span className="text-[11px] px-2 py-0.5 rounded-full" style={{ background: tint(c.color, 0.12), color: c.color }}>{c.name}</span>}
                  {t.archivedAt && <span className="text-[11px] text-stone-400">arhivirano {new Date(t.archivedAt).toLocaleDateString("sr-RS")}</span>}
                </div>
                <div className="flex items-center gap-3 mt-2.5 pt-2 border-t border-stone-100">
                  <button onClick={() => onRestore(t.id)} className="text-[12px] font-medium text-indigo-600 hover:text-indigo-800">Vrati na tablu</button>
                  {confirmId === t.id ? (
                    <span className="flex items-center gap-2">
                      <button onClick={() => onDelete(t.id)} className="text-[12px] font-semibold text-orange-600">Obriši?</button>
                      <button onClick={() => setConfirmId(null)} className="text-[12px] text-stone-400">Ne</button>
                    </span>
                  ) : <button onClick={() => setConfirmId(t.id)} className="text-[12px] font-medium text-stone-400 hover:text-orange-600">Obriši</button>}
                </div>
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}

// ── Board (kad je korisnik prijavljen i podaci učitani) ───────
function Board({ session }) {
  const [tasks, setTasks] = useState([]);
  const [settings, setSettings] = useState(null);
  const [text, setText] = useState("");
  const [newOwner, setNewOwner] = useState(null);
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");
  const [showSettings, setShowSettings] = useState(false);
  const [showDone, setShowDone] = useState(false);
  const [showArchive, setShowArchive] = useState(false);
  const dragId = useRef(null);
  const settingsReady = useRef(false);
  const pauseUntil = useRef(0);          // pauziraj auto-osvežavanje posle lokalne izmene
  const deletedIds = useRef(new Set());  // da osvežavanje ne "vrati" obrisane kartice
  const showSettingsRef = useRef(false); // da osvežavanje ne dira podešavanja dok je panel otvoren
  const pause = () => { pauseUntil.current = Date.now() + 6000; };
  useEffect(() => { showSettingsRef.current = showSettings; }, [showSettings]);

  async function loadAll() {
    const { data: ts } = await sb.from("tasks").select("*").order("created_at", { ascending: false });
    const { data: st } = await sb.from("settings").select("*").eq("id", 1).single();
    if (ts) setTasks(ts.map(taskFromDB).filter((t) => !deletedIds.current.has(t.id)));
    if (st) { setSettings(settingsFromDB(st)); if (!newOwner && st.owners[0]) setNewOwner(st.owners[0].id); }
  }
  async function reloadTasks() {
    if (Date.now() < pauseUntil.current) return;            // ne diraj sveže lokalne izmene
    const { data } = await sb.from("tasks").select("*").order("created_at", { ascending: false });
    if (data) setTasks(data.map(taskFromDB).filter((t) => !deletedIds.current.has(t.id)));
  }
  async function reloadSettings() {
    if (Date.now() < pauseUntil.current) return;            // ne diraj svežu lokalnu izmenu
    if (showSettingsRef.current) return;                    // ne diraj dok je panel otvoren
    const { data } = await sb.from("settings").select("*").eq("id", 1).single();
    if (data) setSettings(settingsFromDB(data));
  }
  useEffect(() => { loadAll(); }, []);

  // auto-arhiviranje na učitavanje
  useEffect(() => {
    if (!settings) return;
    const cutoff = Date.now() - (settings.archiveAfterDays || 7) * 86400000;
    const stale = tasks.filter((t) => !t.archived && t.column === settings.doneColumnId && t.completedAt && t.completedAt < cutoff);
    if (stale.length) {
      const now = Date.now();
      stale.forEach((t) => sb.from("tasks").update({ archived: true, archived_at: new Date(now).toISOString() }).eq("id", t.id));
      setTasks((prev) => prev.map((t) => stale.find((s) => s.id === t.id) ? { ...t, archived: true, archivedAt: now } : t));
    }
  }, [settings]);

  // čuvanje podešavanja u bazu (preskoči prvo postavljanje)
  useEffect(() => {
    if (!settings) return;
    if (!settingsReady.current) { settingsReady.current = true; return; }
    pause();
    sb.from("settings").update(settingsToDB(settings)).eq("id", 1);
  }, [settings]);

  // sinhronizacija sa drugog uređaja: osveži kartice I podešavanja, na fokus i periodično
  useEffect(() => {
    const onFocus = () => { reloadTasks(); reloadSettings(); };
    const iv = setInterval(() => { reloadTasks(); reloadSettings(); }, 15000);
    window.addEventListener("focus", onFocus);
    return () => { clearInterval(iv); window.removeEventListener("focus", onFocus); };
  }, []);

  async function handleSubmit() {
    const t = text.trim(); if (!t || busy || !settings) return;
    setBusy(true); setErr("");
    try {
      const today = new Date().toISOString().slice(0, 10);
      const parsed = await parseTasks(t, today, settings.clients, settings.owners);
      if (!parsed.length) throw new Error("empty");
      const firstCol = settings.columns[0] ? settings.columns[0].id : "todo";
      const rows = parsed.map((p) => ({ ...p, column: firstCol, ownerId: p.ownerId || newOwner }));
      const { data, error } = await sb.from("tasks").insert(rows.map(taskToDB)).select();
      if (error) throw error;
      pause();
      setTasks((prev) => [...(data || []).map(taskFromDB), ...prev]);
      setText("");
    } catch (e) { setErr("Nisam uspeo da razvrstam. Pokušaj ponovo."); }
    finally { setBusy(false); }
  }

  function colPatch(tk, colId) {
    const patch = { column: colId };
    if (colId === settings.doneColumnId && !tk.completedAt) patch.completedAt = Date.now();
    if (colId !== settings.doneColumnId) patch.completedAt = null;
    return patch;
  }
  function applyPatch(id, patch) {
    pause();
    setTasks((prev) => prev.map((tk) => (tk.id === id ? { ...tk, ...patch } : tk)));
    sb.from("tasks").update(patchToDB(patch)).eq("id", id);
  }
  function move(id, dir) {
    const tk = tasks.find((x) => x.id === id); if (!tk) return;
    const i = settings.columns.findIndex((c) => c.id === tk.column);
    const ni = Math.max(0, Math.min(settings.columns.length - 1, i + dir));
    applyPatch(id, colPatch(tk, settings.columns[ni].id));
  }
  function cycleOwner(id) {
    const order = [null, ...settings.owners.map((o) => o.id)];
    const tk = tasks.find((x) => x.id === id); if (!tk) return;
    const ni = (order.indexOf(tk.ownerId) + 1) % order.length;
    applyPatch(id, { ownerId: order[ni] });
  }
  async function del(id) {
    pause();
    deletedIds.current.add(id);
    setTasks((prev) => prev.filter((t) => t.id !== id));
    const { error } = await sb.from("tasks").delete().eq("id", id);
    if (error) { deletedIds.current.delete(id); setErr("Brisanje nije uspelo, pokušaj ponovo."); reloadTasks(); }
  }
  function archive(id) { applyPatch(id, { archived: true, archivedAt: Date.now() }); }
  function restore(id) {
    const firstCol = settings.columns[0] ? settings.columns[0].id : "todo";
    applyPatch(id, { archived: false, archivedAt: null, completedAt: null, column: firstCol });
  }
  const onDrag = (e, id) => { dragId.current = id; e.dataTransfer.effectAllowed = "move"; };
  const onDrop = (colId) => { const id = dragId.current; if (!id) return; const tk = tasks.find((x) => x.id === id); if (tk) applyPatch(id, colPatch(tk, colId)); dragId.current = null; };

  if (!settings) return <div className="min-h-screen bg-stone-100 flex items-center justify-center text-stone-400">Učitavam…</div>;

  const cBy = (id) => settings.clients.find((c) => c.id === id) || null;
  const oBy = (id) => settings.owners.find((o) => o.id === id) || null;
  const visibleColumns = showDone ? settings.columns : settings.columns.filter((c) => c.id !== settings.doneColumnId);
  const doneCount = tasks.filter((t) => !t.archived && t.column === settings.doneColumnId).length;
  const archivedTasks = tasks.filter((t) => t.archived);
  const sortCol = (items) => [...items].sort((a, b) => {
    const pa = PRIO[effectivePriority(a)].rank, pb = PRIO[effectivePriority(b)].rank;
    if (pa !== pb) return pb - pa;
    const da = daysUntil(a.dueDate), db = daysUntil(b.dueDate);
    if (da === null) return 1; if (db === null) return -1; return da - db;
  });

  return (
    <div className="min-h-screen bg-stone-100" style={{ fontFamily: "'Helvetica Neue',Helvetica,Arial,sans-serif" }}>
      <header className="bg-zinc-900 text-stone-100">
        <div className="max-w-6xl mx-auto px-5 sm:px-8 py-4 flex items-center justify-between gap-3">
          <span className="text-2xl font-bold" style={display}>tok</span>
          <div className="flex items-center gap-2">
            <span className="hidden sm:inline text-[12px] text-stone-400">{session.user.email}</span>
            <button onClick={() => setShowSettings(true)} className="text-[13px] text-stone-300 hover:text-white border border-stone-700 rounded-lg px-3 py-1.5">Podešavanja</button>
            <button onClick={() => sb.auth.signOut()} className="text-[13px] text-stone-400 hover:text-white px-2 py-1.5">Odjava</button>
          </div>
        </div>
      </header>

      <main className="max-w-6xl mx-auto px-5 sm:px-8">
        <div className="bg-white border border-stone-200 rounded-xl shadow-sm p-4 mt-5">
          <textarea value={text} onChange={(e) => setText(e.target.value)}
            onKeyDown={(e) => { if ((e.metaKey || e.ctrlKey) && e.key === "Enter") handleSubmit(); }}
            placeholder="Npr. Završi aprilski izveštaj za HighLead do petka, hitno. Obnovi Google OAuth token sledeće nedelje."
            rows={3} className="w-full resize-none text-[15px] text-stone-800 placeholder-stone-400 outline-none leading-relaxed" />
          <div className="flex items-center justify-between mt-2 pt-2 border-t border-stone-100 gap-3 flex-wrap">
            <div className="flex items-center gap-1.5">
              <span className="text-[12px] text-stone-400">za:</span>
              {settings.owners.map((o) => (
                <button key={o.id} onClick={() => setNewOwner(o.id)}
                  className={"text-[12px] px-2.5 py-1 rounded-full border transition " + (newOwner === o.id ? "font-semibold" : "text-stone-500 border-stone-200")}
                  style={newOwner === o.id ? { background: tint(o.color, 0.15), color: o.color, borderColor: tint(o.color, 0.4) } : {}}>{o.name}</button>
              ))}
            </div>
            <button onClick={handleSubmit} disabled={busy || !text.trim()} className="bg-indigo-600 hover:bg-indigo-700 disabled:bg-stone-300 text-white text-sm font-medium px-5 py-2 rounded-lg transition">{busy ? "Razvrstavam…" : "Razvrstaj"}</button>
          </div>
          {err && <p className="text-[13px] text-orange-600 mt-2">{err}</p>}
        </div>

        <div className="flex items-center justify-end gap-2 mt-4">
          <button onClick={() => setShowDone((v) => !v)} className={"text-[13px] rounded-lg px-3 py-1.5 border transition " + (showDone ? "bg-stone-800 text-white border-stone-800" : "bg-white text-stone-600 border-stone-300")}>{showDone ? "Sakrij završeno" : `Završeno (${doneCount})`}</button>
          <button onClick={() => setShowArchive(true)} className="text-[13px] bg-white text-stone-600 border border-stone-300 rounded-lg px-3 py-1.5">Arhiva ({archivedTasks.length})</button>
        </div>

        <div className="flex md:grid gap-3 md:gap-4 mt-4 pb-12 overflow-x-auto md:overflow-visible snap-x snap-mandatory -mx-5 px-5 sm:-mx-8 sm:px-8 md:mx-0 md:px-0"
          style={{ gridTemplateColumns: `repeat(${visibleColumns.length}, minmax(0,1fr))` }}>
          {visibleColumns.map((col) => {
            const isDone = col.id === settings.doneColumnId;
            const items = sortCol(tasks.filter((t) => t.column === col.id && !t.archived));
            return (
              <div key={col.id} onDragOver={(e) => e.preventDefault()} onDrop={() => onDrop(col.id)} className="bg-stone-200/40 rounded-xl p-2.5 min-h-[120px] flex-shrink-0 w-[82vw] max-w-[320px] md:w-auto md:max-w-none snap-start">
                <div className="flex items-center gap-2 px-1.5 py-2">
                  <h2 className="text-[13px] font-semibold text-stone-700 uppercase tracking-wide">{col.label}</h2>
                  <span className="text-[12px] text-stone-400" style={mono}>{items.length}</span>
                </div>
                <div className="space-y-2.5">
                  {items.map((t) => <Card key={t.id} task={t} columns={settings.columns} client={cBy(t.clientId)} owner={oBy(t.ownerId)} onMove={move} onDelete={del} onDrag={onDrag} onCycleOwner={cycleOwner} onArchive={isDone ? archive : undefined} />)}
                  {items.length === 0 && <div className="text-center text-[12px] text-stone-400 py-6 border border-dashed border-stone-300 rounded-lg">prazno</div>}
                </div>
              </div>
            );
          })}
        </div>
      </main>

      {showArchive && <ArchiveModal items={archivedTasks} settings={settings} onRestore={restore} onDelete={del} onClose={() => setShowArchive(false)} />}
      {showSettings && <Settings settings={settings} setSettings={setSettings} onClose={() => setShowSettings(false)} />}
    </div>
  );
}

// ── Auth gate ─────────────────────────────────────────────────
function App() {
  const [session, setSession] = useState(undefined);
  useEffect(() => {
    sb.auth.getSession().then(({ data }) => setSession(data.session));
    const { data: sub } = sb.auth.onAuthStateChange((_e, s) => setSession(s));
    return () => sub.subscription.unsubscribe();
  }, []);

  if (session === undefined) return <div className="min-h-screen bg-stone-100 flex items-center justify-center text-stone-400">…</div>;

  if (!session) {
    return (
      <div className="min-h-screen bg-stone-100 flex flex-col items-center justify-center gap-6 px-6" style={{ fontFamily: "'Helvetica Neue',Helvetica,Arial,sans-serif" }}>
        <span className="text-4xl font-bold text-stone-900" style={display}>tok</span>
        <button onClick={() => sb.auth.signInWithOAuth({ provider: "google", options: { redirectTo: window.location.origin } })}
          className="bg-zinc-900 hover:bg-zinc-800 text-white text-sm font-medium px-6 py-3 rounded-lg transition">Prijavi se Google nalogom</button>
      </div>
    );
  }

  const email = (session.user.email || "").toLowerCase();
  if (CFG.ALLOWED_EMAILS.length && !CFG.ALLOWED_EMAILS.includes(email)) {
    return (
      <div className="min-h-screen bg-stone-100 flex flex-col items-center justify-center gap-4 px-6 text-center" style={{ fontFamily: "'Helvetica Neue',Helvetica,Arial,sans-serif" }}>
        <p className="text-stone-700">Ovaj nalog ({session.user.email}) nema pristup.</p>
        <button onClick={() => sb.auth.signOut()} className="text-sm text-indigo-600 hover:text-indigo-800">Odjava</button>
      </div>
    );
  }

  return <Board session={session} />;
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
