/* global React, Icon, Badge, IconBtn, useLiveQuery, useReceiveFrom, useSendTo, useKvRecord, SendToButton, relTime, fmtDateShort, DAY, db */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ============================================================
// Field visibility — lets users hide optional fields
// ============================================================
const DEFAULT_TODO_FIELDS = {
  priority: true,
  due: true,
  project: true,
  tags: true,
  subtasks: true,
  noteRefs: true,
  description: true,
};

const TODO_FIELD_META = [
  { id: 'priority',    label: 'Priority',     icon: 'flag',         desc: 'High / medium / low badges' },
  { id: 'due',         label: 'Due date',     icon: 'event',        desc: 'Date picker and overdue highlighting' },
  { id: 'project',     label: 'Project',      icon: 'folder',       desc: 'Group tasks into projects' },
  { id: 'tags',        label: 'Tags',         icon: 'tag',          desc: 'Comma-separated free-form labels' },
  { id: 'subtasks',    label: 'Subtasks',     icon: 'checklist',    desc: 'Break down a task into smaller steps' },
  { id: 'noteRefs',    label: 'Linked notes', icon: 'link',         desc: 'Attach notes from the Notes tool' },
  { id: 'description', label: 'Description',  icon: 'notes',        desc: 'Long-form notes / context for the task' },
];

// ============================================================
// Kanban columns — configurable
// ============================================================
const DEFAULT_KANBAN_COLUMNS = [
  { id: 'todo',   title: 'To do',       color: '#60a5fa' },
  { id: 'doing',  title: 'In progress', color: '#fbbf24' },
  { id: 'done',   title: 'Done',        color: '#34d399', isDone: true },
];

function useTodoFields() {
  const [fields, setFields] = useState(DEFAULT_TODO_FIELDS);
  useEffect(() => {
    const load = () => db.kv.get('todoFields').then(r => setFields({ ...DEFAULT_TODO_FIELDS, ...(r?.v || {}) }));
    load();
    const unsub = db.subscribe(({ store, value }) => {
      if (store === 'kv' && (!value || value.k === 'todoFields')) load();
    });
    return unsub;
  }, []);
  const update = (patch) => {
    setFields(prev => {
      const next = { ...prev, ...patch };
      db.kv.put({ k: 'todoFields', v: next });
      return next;
    });
  };
  return [fields, update];
}

function useKanbanColumns() {
  const [cols, setCols] = useState(DEFAULT_KANBAN_COLUMNS);
  useEffect(() => {
    const load = () => db.kv.get('todoKanbanColumns').then(r => {
      if (Array.isArray(r?.v) && r.v.length > 0) setCols(r.v);
      else setCols(DEFAULT_KANBAN_COLUMNS);
    });
    load();
    const unsub = db.subscribe(({ store, value }) => {
      if (store === 'kv' && (!value || value.k === 'todoKanbanColumns')) load();
    });
    return unsub;
  }, []);
  const update = (next) => {
    setCols(next);
    db.kv.put({ k: 'todoKanbanColumns', v: next });
  };
  return [cols, update];
}

// Decide which column a todo belongs to (uses todo.column if set, otherwise:
// done → last "isDone" column, else first non-done column)
function columnOf(todo, cols) {
  if (todo.column && cols.some(c => c.id === todo.column)) return todo.column;
  if (todo.done) {
    const doneCol = [...cols].reverse().find(c => c.isDone);
    return (doneCol || cols[cols.length - 1])?.id;
  }
  const firstOpen = cols.find(c => !c.isDone) || cols[0];
  return firstOpen?.id;
}

// Settings panel for the Tools manager
function TodoSettings() {
  const [fields, update] = useTodoFields();
  const [cols, setCols] = useKanbanColumns();
  const onCount = TODO_FIELD_META.filter(f => fields[f.id]).length;

  const addColumn = async () => {
    const name = await window.lhDialog.prompt({
      title: 'New column',
      placeholder: 'Column title',
      icon: 'view_column',
      confirmLabel: 'Add',
      maxLength: 30,
    });
    if (!name?.trim()) return;
    const palette = ['#60a5fa','#fbbf24','#34d399','#f87171','#c4a0ff','#06b6d4','#f472b6','#a78bfa'];
    const color = palette[cols.length % palette.length];
    const id = name.trim().toLowerCase().replace(/[^\w]+/g, '_') + '_' + Math.random().toString(36).slice(2,5);
    setCols([...cols, { id, title: name.trim(), color }]);
  };

  const renameColumn = async (i) => {
    const newName = await window.lhDialog.prompt({
      title: 'Rename column',
      initial: cols[i].title,
      icon: 'drive_file_rename_outline',
      confirmLabel: 'Rename',
      maxLength: 30,
    });
    if (!newName?.trim()) return;
    setCols(cols.map((c, j) => j === i ? { ...c, title: newName.trim() } : c));
  };

  const setColor = (i, color) => {
    setCols(cols.map((c, j) => j === i ? { ...c, color } : c));
  };

  const toggleDone = (i) => {
    setCols(cols.map((c, j) => j === i ? { ...c, isDone: !c.isDone } : c));
  };

  const move = (i, dir) => {
    const j = i + dir;
    if (j < 0 || j >= cols.length) return;
    const next = [...cols];
    [next[i], next[j]] = [next[j], next[i]];
    setCols(next);
  };

  const removeCol = async (i) => {
    if (cols.length <= 1) {
      await window.lhDialog.confirm({ title: 'Cannot remove', message: 'You need at least one column.', confirmLabel: 'OK' });
      return;
    }
    const ok = await window.lhDialog.confirm({
      title: `Remove "${cols[i].title}"?`,
      message: 'Tasks in this column will move to the first remaining column.',
      confirmLabel: 'Remove',
      danger: true,
      icon: 'delete',
    });
    if (!ok) return;
    setCols(cols.filter((_, j) => j !== i));
  };

  const PALETTE = ['#60a5fa','#fbbf24','#34d399','#f87171','#c4a0ff','#06b6d4','#f472b6','#a78bfa','#94a3b8'];

  return (
    <div className="todo-fields-cfg">
      <div className="todo-fields-cfg-head">
        <Icon name="visibility" />
        <div>
          <div className="title">Visible fields</div>
          <div className="sub">Hide optional fields you don't use to keep the form clean. Title is always visible.</div>
        </div>
        <div className="todo-fields-cfg-count"><strong>{onCount}</strong>/{TODO_FIELD_META.length}</div>
      </div>
      <div className="todo-fields-cfg-list">
        {TODO_FIELD_META.map(f => {
          const on = !!fields[f.id];
          return (
            <button key={f.id} className={`todo-field-row ${on ? 'is-on' : ''}`} onClick={() => update({ [f.id]: !on })}>
              <div className="todo-field-icon"><Icon name={f.icon} /></div>
              <div className="todo-field-body">
                <div className="todo-field-label">{f.label}</div>
                <div className="todo-field-desc">{f.desc}</div>
              </div>
              <div className={`todo-field-toggle ${on ? 'is-on' : ''}`}>
                <span className="todo-field-toggle-dot" />
              </div>
            </button>
          );
        })}
      </div>

      {/* Kanban columns */}
      <div className="todo-fields-cfg-head" style={{ marginTop: 16 }}>
        <Icon name="view_kanban" />
        <div>
          <div className="title">Kanban columns</div>
          <div className="sub">Customize the columns shown when viewing tasks as a board. Mark a column as "Done" to auto-complete tasks dropped there.</div>
        </div>
        <button className="lh-chip" onClick={addColumn}>
          <Icon name="add" />Add
        </button>
      </div>
      <div className="todo-cols-cfg">
        {cols.map((c, i) => (
          <div key={c.id} className="todo-col-row">
            <div className="todo-col-color-wrap">
              <span className="todo-col-color" style={{ background: c.color }} />
              <div className="todo-col-palette">
                {PALETTE.map(p => (
                  <button
                    key={p}
                    className={`todo-col-swatch ${c.color === p ? 'is-active' : ''}`}
                    style={{ background: p }}
                    onClick={() => setColor(i, p)}
                  />
                ))}
              </div>
            </div>
            <div className="todo-col-info">
              <button className="todo-col-title-btn" onClick={() => renameColumn(i)} title="Rename">
                {c.title}
                <Icon name="edit" />
              </button>
              <label className="todo-col-done-toggle" title="Mark tasks as done when dropped here">
                <input
                  type="checkbox"
                  checked={!!c.isDone}
                  onChange={() => toggleDone(i)}
                />
                <span>Completes tasks</span>
              </label>
            </div>
            <div className="todo-col-actions">
              <IconBtn name="arrow_upward"   title="Move up"   onClick={() => move(i, -1)} />
              <IconBtn name="arrow_downward" title="Move down" onClick={() => move(i, 1)} />
              <IconBtn name="delete" tone="danger" title="Remove" onClick={() => removeCol(i)} />
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// ============================================================
// Natural-language quick-add parser
// ------------------------------------------------------------
// Parses things like:
//   "buy milk tomorrow !high #errand"
//   "review PR friday !med #work"
//   "ship it +Q4Launch !high"
// Returns { title, due, priority, tags, project }
// ============================================================
function parseTodoText(raw) {
  let s = ' ' + raw + ' ';
  let priority = null, due = null, tags = [], project = null;

  // !priority
  s = s.replace(/\s!(high|med|medium|low|h|m|l)\b/gi, (_, p) => {
    const map = { h: 'high', high: 'high', m: 'med', med: 'med', medium: 'med', l: 'low', low: 'low' };
    priority = map[p.toLowerCase()];
    return ' ';
  });

  // #tag
  s = s.replace(/\s#([\w-]+)/g, (_, t) => { tags.push(t); return ' '; });

  // +project
  s = s.replace(/\s\+([\w-]+)/g, (_, p) => { project = p; return ' '; });

  // dates: today, tomorrow, mon..sun, "in 3 days", "next week"
  const now = new Date(); now.setHours(0,0,0,0);
  const dayMap = { sun:0, mon:1, tue:2, wed:3, thu:4, fri:5, sat:6, sunday:0, monday:1, tuesday:2, wednesday:3, thursday:4, friday:5, saturday:6 };

  const dayWordRe = /\s(today|tomorrow|tmr|sunday|monday|tuesday|wednesday|thursday|friday|saturday|sun|mon|tue|wed|thu|fri|sat)\b/i;
  const m1 = s.match(dayWordRe);
  if (m1) {
    const w = m1[1].toLowerCase();
    if (w === 'today') due = now.getTime();
    else if (w === 'tomorrow' || w === 'tmr') due = now.getTime() + DAY;
    else {
      const want = dayMap[w];
      const today = now.getDay();
      let diff = (want - today + 7) % 7;
      if (diff === 0) diff = 7;
      due = now.getTime() + diff * DAY;
    }
    s = s.replace(dayWordRe, ' ');
  } else {
    const m2 = s.match(/\sin (\d+) (day|days|week|weeks)\b/i);
    if (m2) {
      const n = parseInt(m2[1], 10);
      const mult = m2[2].startsWith('week') ? 7 : 1;
      due = now.getTime() + n * mult * DAY;
      s = s.replace(/\sin \d+ (day|days|week|weeks)\b/i, ' ');
    } else if (/\snext week\b/i.test(s)) {
      due = now.getTime() + 7 * DAY;
      s = s.replace(/\snext week\b/i, ' ');
    }
  }

  return {
    title: s.trim().replace(/\s+/g, ' '),
    priority, due, tags, project,
  };
}

// ============================================================
// Filter chips
// ============================================================
const FILTERS = [
  { id: 'all',     label: 'All',       icon: 'list_alt' },
  { id: 'today',   label: 'Today',     icon: 'today' },
  { id: 'week',    label: 'This week', icon: 'date_range' },
  { id: 'high',    label: 'High',      icon: 'priority_high' },
  { id: 'done',    label: 'Done',      icon: 'task_alt' },
];

// ============================================================
// Todo Tool
// ============================================================
function TodoTool() {
  const todos = useLiveQuery('todos', { sort: ['updatedAt', 'desc'] });
  const notes = useLiveQuery('notes');
  const [fields] = useTodoFields();
  const [cols] = useKanbanColumns();
  const [view, setView] = useState('list'); // 'list' | 'kanban'
  const [sidebarCollapsed, toggleSidebar] = useToolSidebar('todo');

  // Load view preference
  useEffect(() => {
    db.kv.get('todoView').then(rec => { if (rec?.v) setView(rec.v); });
  }, []);
  const setViewPersist = (v) => {
    setView(v);
    db.kv.put({ k: 'todoView', v });
  };
  const [filter, setFilter] = useState('all');
  const [project, setProject] = useState(null);
  const [selectedId, setSelectedId] = useState(null);
  const [search, setSearch] = useState('');
  const [quickAdd, setQuickAdd] = useState('');
  const [qaProject, setQaProject] = useState(null); // default project for new todos
  const [qaProjectOpen, setQaProjectOpen] = useState(false);
  const [extraProjects, setExtraProjects] = useState([]); // user-created empty projects
  const quickAddRef = useRef(null);
  const qaProjectRef = useRef(null);

  // Receive from other tools
  useReceiveFrom('todo', (payload) => {
    if (payload?.selectId) {
      setSelectedId(payload.selectId);
      return;
    }
    if (payload?.text) setQuickAdd(payload.text.slice(0, 200));
    quickAddRef.current?.focus();
  });

  const projects = useMemo(() => {
    const set = new Set();
    (todos || []).forEach(t => { if (t.project) set.add(t.project); });
    extraProjects.forEach(p => set.add(p));
    return [...set].sort();
  }, [todos, extraProjects]);

  const filtered = useMemo(() => {
    if (!todos) return [];
    const today = new Date(); today.setHours(0,0,0,0);
    const todayTs = today.getTime();
    const weekTs = todayTs + DAY * 7;

    return todos.filter(t => {
      if (project && t.project !== project) return false;
      if (search) {
        const q = search.toLowerCase();
        if (!t.title.toLowerCase().includes(q) &&
            !(t.tags || []).some(tg => tg.toLowerCase().includes(q))) return false;
      }
      switch (filter) {
        case 'today': return !t.done && t.due && t.due >= todayTs && t.due < todayTs + DAY;
        case 'week':  return !t.done && t.due && t.due >= todayTs && t.due < weekTs;
        case 'high':  return !t.done && t.priority === 'high';
        case 'done':  return t.done;
        case 'all':
        default:      return !t.done;
      }
    }).sort((a,b) => {
      // Group: open before done; within open, by due asc (null last), then priority
      if (a.done !== b.done) return a.done ? 1 : -1;
      if (!a.done && !b.done) {
        const ad = a.due ?? Infinity, bd = b.due ?? Infinity;
        if (ad !== bd) return ad - bd;
        const pri = { high: 0, med: 1, low: 2, undefined: 3 };
        return (pri[a.priority] ?? 3) - (pri[b.priority] ?? 3);
      }
      return (b.updatedAt || 0) - (a.updatedAt || 0);
    });
  }, [todos, filter, project, search]);

  const selected = useMemo(() => filtered.find(t => t.id === selectedId) || filtered[0], [filtered, selectedId]);

  // ---- Actions
  const addTodo = useCallback(() => {
    const text = quickAdd.trim();
    if (!text) return;
    const parsed = parseTodoText(text);
    if (!parsed.title) return;
    db.todos.put({
      title: parsed.title,
      done: false,
      priority: parsed.priority,
      due: parsed.due,
      // Inline +project in text wins; otherwise the picker's choice
      project: parsed.project || qaProject || null,
      tags: parsed.tags,
      subtasks: [],
    });
    setQuickAdd('');
  }, [quickAdd, qaProject]);

  // Close project picker on outside click
  useEffect(() => {
    if (!qaProjectOpen) return;
    const onDoc = (e) => {
      if (qaProjectRef.current && !qaProjectRef.current.contains(e.target)) {
        setQaProjectOpen(false);
      }
    };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [qaProjectOpen]);

  // Persist + load quick-add default project + extra projects list
  useEffect(() => {
    db.kv.get('todoQaProject').then(rec => { if (rec?.v !== undefined) setQaProject(rec.v); });
    db.kv.get('todoProjects').then(rec => { if (Array.isArray(rec?.v)) setExtraProjects(rec.v); });
  }, []);
  const setQaProjectPersist = (p) => {
    setQaProject(p);
    db.kv.put({ k: 'todoQaProject', v: p });
  };
  const persistExtraProjects = (list) => {
    setExtraProjects(list);
    db.kv.put({ k: 'todoProjects', v: list });
  };

  const createNewProject = async ({ andFilter = false, andDefault = true } = {}) => {
    const name = await window.lhDialog.prompt({
      title: 'New project',
      message: andFilter
        ? 'Adds a new project. New quick-add tasks will default to it.'
        : 'Future quick-add tasks will default to this project until you change it.',
      placeholder: 'Project name',
      icon: 'create_new_folder',
      confirmLabel: 'Create',
      maxLength: 40,
    });
    if (!name) return;
    const clean = name.trim();
    if (!clean) return;
    if (!projects.includes(clean) && !extraProjects.includes(clean)) {
      persistExtraProjects([...extraProjects, clean]);
    }
    if (andDefault) setQaProjectPersist(clean);
    if (andFilter) setProject(clean);
    setQaProjectOpen(false);
  };

  const toggleDone = (todo) => db.todos.put({ ...todo, done: !todo.done });

  const updateTodo = (todo, patch) => db.todos.put({ ...todo, ...patch });

  const deleteTodo = (todo) => db.todos.delete(todo.id);

  const addSubtask = (todo, title) => {
    const subtasks = [...(todo.subtasks || []), { id: db.uid(), title, done: false }];
    db.todos.put({ ...todo, subtasks });
  };

  const toggleSubtask = (todo, subId) => {
    const subtasks = (todo.subtasks || []).map(s => s.id === subId ? { ...s, done: !s.done } : s);
    db.todos.put({ ...todo, subtasks });
  };

  const removeSubtask = (todo, subId) => {
    const subtasks = (todo.subtasks || []).filter(s => s.id !== subId);
    db.todos.put({ ...todo, subtasks });
  };

  // Drag-drop note onto todo
  const onDropOnTodo = (todo, e) => {
    e.preventDefault();
    e.currentTarget.classList.remove('drop-target');
    const data = e.dataTransfer.getData('application/x-lifehub');
    if (!data) return;
    try {
      const payload = JSON.parse(data);
      if (payload.type === 'note' && payload.id) {
        const refs = todo.noteRefs || [];
        if (!refs.includes(payload.id)) {
          db.todos.put({ ...todo, noteRefs: [...refs, payload.id] });
        }
      }
    } catch (err) {}
  };

  // Stats
  const stats = useMemo(() => {
    if (!todos) return { open: 0, done: 0, today: 0, overdue: 0 };
    const today = new Date(); today.setHours(0,0,0,0);
    const todayTs = today.getTime();
    let open = 0, done = 0, todayCount = 0, overdue = 0;
    for (const t of todos) {
      if (t.done) done++;
      else {
        open++;
        if (t.due && t.due >= todayTs && t.due < todayTs + DAY) todayCount++;
        if (t.due && t.due < todayTs) overdue++;
      }
    }
    return { open, done, today: todayCount, overdue };
  }, [todos]);

  return (
    <div className="tool">
      {/* Quick-add bar */}
      <div className="todo-quickadd">
        <Icon name="add_task" />
        <input
          ref={quickAddRef}
          className="todo-quickadd-input"
          placeholder='Add a task — "ship it tomorrow !high #design"  (try natural language)'
          value={quickAdd}
          onChange={e => setQuickAdd(e.target.value)}
          onKeyDown={e => { if (e.key === 'Enter') addTodo(); }}
        />
        {quickAdd && (
          <QuickAddPreview parsed={parseTodoText(quickAdd)} />
        )}
        <div className="todo-qa-project" ref={qaProjectRef} style={{ display: fields.project ? '' : 'none' }}>
          <button
            className={`todo-qa-project-btn ${qaProject ? 'has-value' : ''}`}
            onClick={() => setQaProjectOpen(o => !o)}
            title="Default project for new tasks"
          >
            <Icon name={qaProject ? 'folder' : 'folder_off'} />
            <span>{qaProject || 'No project'}</span>
            <Icon name="expand_more" className="trail" />
          </button>
          {qaProjectOpen && (
            <div className="todo-qa-project-menu">
              <div className="todo-qa-project-head">Default project</div>
              <button
                className={`todo-qa-project-item ${!qaProject ? 'is-active' : ''}`}
                onClick={() => { setQaProjectPersist(null); setQaProjectOpen(false); }}
              >
                <Icon name="folder_off" />
                <span>No project</span>
                {!qaProject && <Icon name="check" className="trail" />}
              </button>
              {projects.map(p => (
                <button
                  key={p}
                  className={`todo-qa-project-item ${qaProject === p ? 'is-active' : ''}`}
                  onClick={() => { setQaProjectPersist(p); setQaProjectOpen(false); }}
                >
                  <Icon name="folder" />
                  <span>{p}</span>
                  {qaProject === p && <Icon name="check" className="trail" />}
                </button>
              ))}
              <div className="todo-qa-project-divider" />
              <button className="todo-qa-project-item is-new" onClick={createNewProject}>
                <Icon name="add" />
                <span>New project…</span>
              </button>
            </div>
          )}
        </div>
        <button className="lh-btn primary" onClick={addTodo} disabled={!quickAdd.trim()}>
          <Icon name="add" />
          Add
        </button>
        <div className="todo-view-pick">
          <button
            className={`todo-view-btn ${view === 'list' ? 'is-active' : ''}`}
            onClick={() => setViewPersist('list')}
            title="List view"
          ><Icon name="view_list" /></button>
          <button
            className={`todo-view-btn ${view === 'kanban' ? 'is-active' : ''}`}
            onClick={() => setViewPersist('kanban')}
            title="Kanban view"
          ><Icon name="view_kanban" /></button>
        </div>
      </div>

      <div className="todo-stats">
        <StatCard label="Open" value={stats.open} icon="radio_button_unchecked" />
        <StatCard label="Today" value={stats.today} icon="today" tone="primary" />
        <StatCard label="Overdue" value={stats.overdue} icon="error_outline" tone={stats.overdue ? 'danger' : 'neutral'} />
        <StatCard label="Done" value={stats.done} icon="check_circle" tone="success" />
      </div>

      {view === 'kanban' ? (
        <TodoKanban
          todos={todos || []}
          cols={cols}
          fields={fields}
          notes={notes || []}
          search={search}
          setSearch={setSearch}
          filter={filter}
          project={project}
        />
      ) : (
      <div className={`tool-twopane todo-twopane ${sidebarCollapsed ? 'is-list-collapsed' : ''}`}>
        {/* List */}
        <div className="tool-list">
          <div className="tool-list-collapsed-rail" onClick={toggleSidebar} title="Expand sidebar">
            <Icon name="chevron_right" />
          </div>
          <div className="tool-list-head">
            <div className="todo-filters">
              {FILTERS.map(f => (
                <button
                  key={f.id}
                  className={`lh-chip ${filter === f.id ? 'is-active' : ''}`}
                  onClick={() => setFilter(f.id)}
                >
                  <Icon name={f.icon} />
                  {f.label}
                </button>
              ))}
            </div>
            <ToolSidebarToggle collapsed={sidebarCollapsed} onToggle={toggleSidebar} />
          </div>

          {/* Project filter list with a + button to create one */}
          {fields.project && (
          <div className="todo-projects">
            <button
              className={`todo-proj ${!project ? 'is-active' : ''}`}
              onClick={() => setProject(null)}
            >
              <Icon name="inbox" />
              <span>All projects</span>
            </button>
            {projects.map(p => (
              <button
                key={p}
                className={`todo-proj ${project === p ? 'is-active' : ''}`}
                onClick={() => setProject(p)}
              >
                <Icon name="folder" />
                <span>{p}</span>
              </button>
            ))}
            <button
              className="todo-proj is-new"
              onClick={() => createNewProject({ andFilter: true })}
              title="Create a new project"
            >
              <Icon name="add" />
              <span>New project…</span>
            </button>
          </div>
          )}

          <div className="tool-list-search">
            <Icon name="search" />
            <input
              placeholder="Filter tasks…"
              value={search}
              onChange={e => setSearch(e.target.value)}
            />
          </div>

          <div className="tool-list-scroll">
            {filtered.length === 0 ? (
              <div className="lh-empty" style={{ padding: '40px 16px' }}>
                <Icon name="check_circle" />
                <div className="title">All clear</div>
                <div className="sub">No tasks match this filter.</div>
              </div>
            ) : filtered.map(todo => (
              <TodoListItem
                key={todo.id}
                todo={todo}
                fields={fields}
                selected={selected?.id === todo.id}
                onSelect={() => setSelectedId(todo.id)}
                onToggleDone={() => toggleDone(todo)}
                onDrop={(e) => onDropOnTodo(todo, e)}
              />
            ))}
          </div>
        </div>

        {/* Detail */}
        <div className="tool-detail">
          {selected ? (
            <TodoDetail
              todo={selected}
              notes={notes || []}
              fields={fields}
              onUpdate={(patch) => updateTodo(selected, patch)}
              onToggleDone={() => toggleDone(selected)}
              onDelete={() => { deleteTodo(selected); setSelectedId(null); }}
              onAddSubtask={(title) => addSubtask(selected, title)}
              onToggleSubtask={(id) => toggleSubtask(selected, id)}
              onRemoveSubtask={(id) => removeSubtask(selected, id)}
            />
          ) : (
            <div className="lh-empty">
              <Icon name="task_alt" />
              <div className="title">Pick a task to view details</div>
              <div className="sub">Or add one above with natural language.</div>
            </div>
          )}
        </div>
      </div>
      )}
    </div>
  );
}

// ============================================================
// Quick-add live parse preview
// ============================================================
function QuickAddPreview({ parsed }) {
  const bits = [];
  if (parsed.priority) bits.push(<Badge key="p" tone={parsed.priority}>{parsed.priority}</Badge>);
  if (parsed.due) bits.push(<Badge key="d" tone="primary"><Icon name="event" />{relTime(parsed.due)}</Badge>);
  if (parsed.project) bits.push(<Badge key="pr" tone="neutral"><Icon name="folder" />{parsed.project}</Badge>);
  for (const tag of parsed.tags) bits.push(<Badge key={'t'+tag} tone="neutral">#{tag}</Badge>);
  if (bits.length === 0) return null;
  return <div className="todo-qa-preview">{bits}</div>;
}

// ============================================================
// Stat card
// ============================================================
function StatCard({ label, value, icon, tone = 'neutral' }) {
  return (
    <div className={`todo-stat tone-${tone}`}>
      <Icon name={icon} />
      <div className="todo-stat-meta">
        <div className="v">{value}</div>
        <div className="l">{label}</div>
      </div>
    </div>
  );
}

// ============================================================
// List item
// ============================================================
function TodoListItem({ todo, fields = DEFAULT_TODO_FIELDS, selected, onSelect, onToggleDone, onDrop }) {
  const overdue = !todo.done && todo.due && todo.due < Date.now() - 60000;
  const subDone = (todo.subtasks || []).filter(s => s.done).length;
  const subTotal = (todo.subtasks || []).length;
  return (
    <div
      role="button"
      tabIndex={0}
      className={`todo-row ${selected ? 'is-selected' : ''} ${todo.done ? 'is-done' : ''}`}
      onClick={onSelect}
      onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onSelect(); } }}
      onDragOver={(e) => { e.preventDefault(); e.currentTarget.classList.add('drop-target'); }}
      onDragLeave={(e) => e.currentTarget.classList.remove('drop-target')}
      onDrop={onDrop}
    >
      <button
        className={`todo-check ${todo.done ? 'is-on' : ''}`}
        onClick={(e) => { e.stopPropagation(); onToggleDone(); }}
        title="Toggle done"
      >
        {todo.done && <Icon name="check" />}
      </button>
      <div className="todo-row-main">
        <div className="todo-row-title">{todo.title}</div>
        <div className="todo-row-meta">
          {fields.priority && todo.priority && <span className={`todo-prio prio-${todo.priority}`} />}
          {fields.due && todo.due && (
            <span className={`todo-due ${overdue ? 'is-overdue' : ''}`}>
              <Icon name="event" />
              {relTime(todo.due)}
            </span>
          )}
          {fields.subtasks && subTotal > 0 && (
            <span className="todo-sub-count">
              <Icon name="checklist" />
              {subDone}/{subTotal}
            </span>
          )}
          {fields.project && todo.project && <span className="todo-proj-chip">{todo.project}</span>}
          {fields.noteRefs && (todo.noteRefs || []).length > 0 && (
            <span className="todo-note-ref" title="Linked notes">
              <Icon name="link" />
              {todo.noteRefs.length}
            </span>
          )}
          {fields.tags && (todo.tags || []).slice(0, 3).map(t => (
            <span className="todo-tag" key={t}>#{t}</span>
          ))}
        </div>
      </div>
      <PinButton type="todo" id={todo.id} className="row-pin" />
    </div>
  );
}

// ============================================================
// Detail panel
// ============================================================
function TodoDetail({ todo, notes, fields = DEFAULT_TODO_FIELDS, onUpdate, onToggleDone, onDelete, onAddSubtask, onToggleSubtask, onRemoveSubtask }) {
  const [subText, setSubText] = useState('');
  const linkedNotes = useMemo(
    () => (todo.noteRefs || []).map(id => notes.find(n => n.id === id)).filter(Boolean),
    [todo.noteRefs, notes]
  );
  const showMetaGrid = fields.priority || fields.due || fields.project || fields.tags;

  return (
    <>
      <div className="tool-detail-head">
        <button
          className={`todo-check lg ${todo.done ? 'is-on' : ''}`}
          onClick={onToggleDone}
        >
          {todo.done && <Icon name="check" />}
        </button>
        <input
          className="todo-detail-title"
          value={todo.title}
          onChange={e => onUpdate({ title: e.target.value })}
        />
        <div style={{ flex: 1 }} />
        <IconBtn name="delete" tone="danger" title="Delete" onClick={onDelete} />
      </div>

      <div className="tool-detail-body">
        {showMetaGrid && (
          <div className="todo-meta-grid">
            {/* Priority */}
            {fields.priority && (
              <div className="todo-meta">
                <div className="todo-meta-label">Priority</div>
                <div className="todo-prio-pick">
                  {[null, 'low', 'med', 'high'].map(p => (
                    <button
                      key={p || 'none'}
                      className={`todo-prio-btn ${todo.priority === p ? 'is-active' : ''} ${p ? 'has-' + p : ''}`}
                      onClick={() => onUpdate({ priority: p })}
                    >
                      {p ? p : 'none'}
                    </button>
                  ))}
                </div>
              </div>
            )}

            {/* Due date */}
            {fields.due && (
              <div className="todo-meta">
                <div className="todo-meta-label">Due</div>
                <div className="todo-due-pick">
                  <input
                    type="date"
                    className="lh-input"
                    value={todo.due ? new Date(todo.due).toISOString().slice(0,10) : ''}
                    onChange={e => {
                      if (!e.target.value) onUpdate({ due: null });
                      else {
                        const d = new Date(e.target.value);
                        d.setHours(9,0,0,0);
                        onUpdate({ due: d.getTime() });
                      }
                    }}
                  />
                  {todo.due && (
                    <IconBtn name="close" title="Clear" onClick={() => onUpdate({ due: null })} />
                  )}
                </div>
              </div>
            )}

            {/* Project */}
            {fields.project && (
              <div className="todo-meta">
                <div className="todo-meta-label">Project</div>
                <input
                  className="lh-input"
                  placeholder="No project"
                  value={todo.project || ''}
                  onChange={e => onUpdate({ project: e.target.value || null })}
                />
              </div>
            )}

            {/* Tags */}
            {fields.tags && (
              <div className="todo-meta">
                <div className="todo-meta-label">Tags</div>
                <input
                  className="lh-input"
                  placeholder="comma, separated"
                  value={(todo.tags || []).join(', ')}
                  onChange={e => onUpdate({ tags: e.target.value.split(',').map(s => s.trim()).filter(Boolean) })}
                />
              </div>
            )}
          </div>
        )}

        {/* Subtasks */}
        {fields.subtasks && (
        <div className="todo-section">
          <div className="todo-section-head">
            <Icon name="checklist" />
            <span>Subtasks</span>
            {(todo.subtasks || []).length > 0 && (
              <span className="count">
                {(todo.subtasks || []).filter(s => s.done).length}/{(todo.subtasks || []).length}
              </span>
            )}
          </div>
          {(todo.subtasks || []).length > 0 && (
            <div className="todo-subs">
              {todo.subtasks.map(s => (
                <div key={s.id} className={`todo-sub ${s.done ? 'is-done' : ''}`}>
                  <button
                    className={`todo-check sm ${s.done ? 'is-on' : ''}`}
                    onClick={() => onToggleSubtask(s.id)}
                  >
                    {s.done && <Icon name="check" />}
                  </button>
                  <span className="todo-sub-title">{s.title}</span>
                  <IconBtn name="close" title="Remove" onClick={() => onRemoveSubtask(s.id)} />
                </div>
              ))}
            </div>
          )}
          <form
            className="todo-sub-add"
            onSubmit={e => {
              e.preventDefault();
              const v = subText.trim();
              if (!v) return;
              onAddSubtask(v);
              setSubText('');
            }}
          >
            <Icon name="add" />
            <input
              placeholder="Add a subtask…"
              value={subText}
              onChange={e => setSubText(e.target.value)}
            />
          </form>
        </div>
        )}

        {/* Time tracked (Time Tracker integration) */}
        <TodoTimeTracked todo={todo}></TodoTimeTracked>

        {/* Linked notes */}
        {fields.noteRefs && (
        <div className="todo-section">
          <div className="todo-section-head">
            <Icon name="link" />
            <span>Linked notes</span>
            <span className="todo-section-hint">Drag a note here, or pick one</span>
          </div>
          <div
            className="todo-note-drop"
            onDragOver={(e) => { e.preventDefault(); e.currentTarget.classList.add('drop-active'); }}
            onDragLeave={(e) => e.currentTarget.classList.remove('drop-active')}
            onDrop={(e) => {
              e.preventDefault();
              e.currentTarget.classList.remove('drop-active');
              const data = e.dataTransfer.getData('application/x-lifehub');
              if (!data) return;
              try {
                const p = JSON.parse(data);
                if (p.type === 'note' && p.id) {
                  const refs = todo.noteRefs || [];
                  if (!refs.includes(p.id)) onUpdate({ noteRefs: [...refs, p.id] });
                }
              } catch (err) {}
            }}
          >
            {linkedNotes.length === 0 ? (
              <div className="todo-note-drop-empty">
                <Icon name="drag_indicator" />
                Drop a note from the Notes tool here
              </div>
            ) : linkedNotes.map(n => (
              <div className="todo-note-pill" key={n.id}>
                <Icon name="description" />
                <span>{n.title}</span>
                <IconBtn
                  name="close"
                  title="Unlink"
                  onClick={() => onUpdate({ noteRefs: (todo.noteRefs || []).filter(x => x !== n.id) })}
                />
              </div>
            ))}
          </div>
          <select
            className="lh-input"
            style={{ marginTop: 8 }}
            value=""
            onChange={(e) => {
              if (!e.target.value) return;
              const refs = todo.noteRefs || [];
              if (!refs.includes(e.target.value)) onUpdate({ noteRefs: [...refs, e.target.value] });
              e.target.value = '';
            }}
          >
            <option value="">+ Link existing note…</option>
            {notes.filter(n => !(todo.noteRefs || []).includes(n.id)).map(n => (
              <option key={n.id} value={n.id}>{n.title}</option>
            ))}
          </select>
        </div>
        )}

        {/* Notes / description */}
        {fields.description && (
        <div className="todo-section">
          <div className="todo-section-head">
            <Icon name="notes" />
            <span>Description</span>
          </div>
          <textarea
            className="lh-input"
            placeholder="Add notes, context, links…"
            value={todo.notes || ''}
            onChange={e => onUpdate({ notes: e.target.value })}
            rows={4}
          />
        </div>
        )}

        <div className="todo-foot-meta">
          Created {relTime(todo.createdAt)} · Updated {relTime(todo.updatedAt)}
        </div>
      </div>
    </>
  );
}

window.TodoTool = TodoTool;

// ============================================================
// Time-tracked section — integration with the Time Tracker tool.
// Shows total time logged against this todo and a one-click
// "Start timer" that prefills description + project.
// ============================================================
function TodoTimeTracked({ todo }) {
  const { send, isToolEnabled } = useSendTo();
  const enabled = isToolEnabled('timetracker') && !!window.ttStartTimer;
  const sessions = useLiveQuery(enabled ? 'timeEntries' : null);
  const tasks = useLiveQuery(enabled ? 'timeTasks' : null);
  const running = useKvRecord('timeTrackerRunning');
  // running may be a list (concurrent timers) or a legacy single object/null
  const runningList = useMemo(() => {
    if (!running) return [];
    return Array.isArray(running) ? running : [running];
  }, [running]);

  // Tick while any of this todo's timers run so the total stays live
  const myTaskIds = useMemo(
    () => new Set((tasks || []).filter(t => t.todoId === todo.id).map(t => t.id)),
    [tasks, todo.id]
  );
  const runningHere = enabled && runningList.some(r => r.todoId === todo.id || myTaskIds.has(r.taskId));
  const [, setTick] = useState(0);
  useEffect(() => {
    if (!runningHere) return;
    const t = setInterval(() => setTick(x => x + 1), 1000);
    return () => clearInterval(t);
  }, [runningHere]);

  const { totalMs, count } = useMemo(() => {
    const mine = (sessions || []).filter(s => myTaskIds.has(s.taskId));
    let ms = mine.reduce((a, s) => a + Math.max(0, (s.stoppedAt || Date.now()) - s.startedAt), 0);
    for (const r of runningList) {
      if (r.todoId === todo.id || myTaskIds.has(r.taskId)) ms += Date.now() - r.startedAt;
    }
    return { totalMs: ms, count: mine.length };
  }, [sessions, myTaskIds, todo.id, runningList, runningHere ? Date.now() : 0]);

  if (!enabled) return null;

  const startTimer = () => {
    send('timetracker', {
      startFromTodo: { id: todo.id, title: todo.title, project: todo.project || null, tags: todo.tags || [] },
    });
  };

  return (
    <div className="todo-section">
      <div className="todo-section-head">
        <Icon name="timelapse" />
        <span>Time tracked</span>
      </div>
      <div className="trk-todo-summary">
        <span className="trk-todo-total">
          <strong>{window.ttFmtDuration(totalMs, { seconds: false })}</strong>
          {count > 0 ? `across ${count} ${count === 1 ? 'session' : 'sessions'}` : 'logged so far'}
        </span>
        {runningHere ? (
          <button className="lh-btn danger" onClick={() => window.ttStopTimer()}>
            <Icon name="stop" />Stop timer
          </button>
        ) : (
          <button className="lh-btn ghost" onClick={startTimer}>
            <Icon name="play_arrow" />Start timer
          </button>
        )}
      </div>
    </div>
  );
}

// ============================================================
// Kanban view
// ============================================================
function TodoKanban({ todos, cols, fields, notes, search, setSearch, filter, project }) {
  const [selectedId, setSelectedId] = useState(null);

  const today = useMemo(() => { const d = new Date(); d.setHours(0,0,0,0); return d.getTime(); }, []);
  const visible = useMemo(() => {
    return todos.filter(t => {
      if (project && t.project !== project) return false;
      if (search) {
        const q = search.toLowerCase();
        if (!t.title.toLowerCase().includes(q) &&
            !(t.tags || []).some(tg => tg.toLowerCase().includes(q))) return false;
      }
      switch (filter) {
        case 'today':  return t.due && t.due >= today && t.due < today + DAY;
        case 'week':   return t.due && t.due >= today && t.due < today + DAY * 7;
        case 'high':   return t.priority === 'high';
        case 'done':   return t.done;
        case 'all':
        default:       return true;
      }
    });
  }, [todos, search, filter, project, today]);

  const byColumn = useMemo(() => {
    const map = new Map();
    for (const c of cols) map.set(c.id, []);
    for (const t of visible) {
      const cid = columnOf(t, cols);
      if (!map.has(cid)) map.set(cid, []);
      map.get(cid).push(t);
    }
    return map;
  }, [visible, cols]);

  const handleDrop = (todo, col) => {
    const patch = { column: col.id };
    if (col.isDone && !todo.done) patch.done = true;
    if (!col.isDone && todo.done) patch.done = false;
    db.todos.put({ ...todo, ...patch });
  };

  const selected = todos.find(t => t.id === selectedId);

  return (
    <div className="todo-kanban-wrap">
      <div className="todo-kanban-search">
        <Icon name="search" />
        <input
          placeholder="Filter tasks across columns…"
          value={search}
          onChange={e => setSearch(e.target.value)}
        />
      </div>
      <div className="todo-kanban">
        {cols.map(col => (
          <KanbanColumn
            key={col.id}
            col={col}
            tasks={byColumn.get(col.id) || []}
            fields={fields}
            onDropTask={(t) => handleDrop(t, col)}
            onSelect={setSelectedId}
            selectedId={selectedId}
          />
        ))}
      </div>

      {selected && (
        <div className="todo-drawer-overlay" onClick={() => setSelectedId(null)}>
          <div className="todo-drawer" onClick={e => e.stopPropagation()}>
            <TodoDetail
              todo={selected}
              notes={notes}
              fields={fields}
              onUpdate={(patch) => db.todos.put({ ...selected, ...patch })}
              onToggleDone={() => db.todos.put({ ...selected, done: !selected.done })}
              onDelete={() => { db.todos.delete(selected.id); setSelectedId(null); }}
              onAddSubtask={(title) => {
                const subtasks = [...(selected.subtasks || []), { id: db.uid(), title, done: false }];
                db.todos.put({ ...selected, subtasks });
              }}
              onToggleSubtask={(id) => {
                const subtasks = (selected.subtasks || []).map(s => s.id === id ? { ...s, done: !s.done } : s);
                db.todos.put({ ...selected, subtasks });
              }}
              onRemoveSubtask={(id) => {
                const subtasks = (selected.subtasks || []).filter(s => s.id !== id);
                db.todos.put({ ...selected, subtasks });
              }}
            />
          </div>
        </div>
      )}
    </div>
  );
}

function KanbanColumn({ col, tasks, fields, onDropTask, onSelect, selectedId }) {
  const [dragOver, setDragOver] = useState(false);
  return (
    <div
      className={`kanban-col ${dragOver ? 'is-drop-target' : ''}`}
      onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
      onDragLeave={() => setDragOver(false)}
      onDrop={(e) => {
        e.preventDefault();
        setDragOver(false);
        try {
          const data = JSON.parse(e.dataTransfer.getData('application/x-lifehub-task') || 'null');
          if (data?.todo) onDropTask(data.todo);
        } catch {}
      }}
    >
      <div className="kanban-col-head">
        <span className="kanban-col-dot" style={{ background: col.color }} />
        <span className="kanban-col-title">{col.title}</span>
        <span className="kanban-col-count">{tasks.length}</span>
        {col.isDone && <Icon name="task_alt" className="kanban-col-done-flag" />}
      </div>
      <div className="kanban-col-body">
        {tasks.length === 0 ? (
          <div className="kanban-col-empty">Drop tasks here</div>
        ) : tasks.map(todo => (
          <KanbanCard
            key={todo.id}
            todo={todo}
            fields={fields}
            isSelected={selectedId === todo.id}
            onClick={() => onSelect(todo.id)}
          />
        ))}
      </div>
    </div>
  );
}

function KanbanCard({ todo, fields, isSelected, onClick }) {
  const overdue = !todo.done && todo.due && todo.due < Date.now() - 60000;
  const subDone = (todo.subtasks || []).filter(s => s.done).length;
  const subTotal = (todo.subtasks || []).length;
  return (
    <div
      className={`kanban-card ${isSelected ? 'is-selected' : ''} ${todo.done ? 'is-done' : ''}`}
      onClick={onClick}
      draggable
      onDragStart={(e) => {
        e.dataTransfer.setData('application/x-lifehub-task', JSON.stringify({ todo }));
        e.dataTransfer.effectAllowed = 'move';
      }}
    >
      {fields.priority && todo.priority && (
        <span className={`kanban-card-prio prio-${todo.priority}`}>{todo.priority}</span>
      )}
      <div className="kanban-card-title">{todo.title}</div>
      <div className="kanban-card-meta">
        {fields.due && todo.due && (
          <span className={`kanban-card-due ${overdue ? 'is-overdue' : ''}`}>
            <Icon name="event" />{relTime(todo.due)}
          </span>
        )}
        {fields.subtasks && subTotal > 0 && (
          <span className="kanban-card-subs">
            <Icon name="checklist" />{subDone}/{subTotal}
          </span>
        )}
        {fields.project && todo.project && (
          <span className="kanban-card-proj">{todo.project}</span>
        )}
        {fields.noteRefs && (todo.noteRefs || []).length > 0 && (
          <span className="kanban-card-link">
            <Icon name="link" />{todo.noteRefs.length}
          </span>
        )}
      </div>
      {fields.tags && (todo.tags || []).length > 0 && (
        <div className="kanban-card-tags">
          {todo.tags.slice(0, 4).map(t => <span key={t} className="kanban-card-tag">#{t}</span>)}
        </div>
      )}
    </div>
  );
}

// Register tool-specific settings panel
window.toolSettingsRegistry = window.toolSettingsRegistry || {};
window.toolSettingsRegistry.todo = TodoSettings;
