// Timeline & Calendar — per-campaign task tracker, dengan list view + month
// calendar grid. Workflow standar: setup → launch → promote → collect →
// analyze → present. Auto-template di-seed lewat tombol 'Load template'.

const { useState: useState_tl, useEffect: useEffect_tl } = React;

const CATEGORY_META = {
  setup:            { label: 'Setup',           color: 'oklch(0.55 0.18 265)', bg: 'oklch(0.95 0.05 265)', emoji: '⚙️' },
  launch:           { label: 'Launch',          color: 'oklch(0.55 0.18 305)', bg: 'oklch(0.95 0.05 305)', emoji: '🚀' },
  // Promote dipisah jadi online (digital channels — biru) vs offline
  // (physical channels — oranye). Keep `promote` legacy dengan warna
  // amber netral untuk task-task lama.
  promote_online:   { label: 'Promote Online',  color: 'oklch(0.50 0.18 230)', bg: 'oklch(0.95 0.06 230)', emoji: '🌐' },
  promote_offline:  { label: 'Promote Offline', color: 'oklch(0.55 0.16 35)',  bg: 'oklch(0.96 0.05 35)',  emoji: '📍' },
  promote:          { label: 'Promote',         color: 'oklch(0.55 0.16 75)',  bg: 'oklch(0.96 0.05 75)',  emoji: '📢' },
  collect:          { label: 'Collect',         color: 'oklch(0.55 0.16 25)',  bg: 'oklch(0.96 0.05 25)',  emoji: '📥' },
  analyze:          { label: 'Analyze',         color: 'oklch(0.50 0.18 200)', bg: 'oklch(0.95 0.06 200)', emoji: '📊' },
  present:          { label: 'Present',         color: 'oklch(0.55 0.18 145)', bg: 'oklch(0.95 0.06 145)', emoji: '🎤' },
  other:            { label: 'Other',           color: 'var(--ink-2)',         bg: 'var(--bg-2)',          emoji: '📝' },
};

function dateKey(d) {
  if (!d) return null;
  const x = new Date(d);
  return `${x.getFullYear()}-${String(x.getMonth() + 1).padStart(2, '0')}-${String(x.getDate()).padStart(2, '0')}`;
}

function fmtDate(d) {
  if (!d) return null;
  return new Date(d).toLocaleDateString('id-ID', { day: '2-digit', month: 'short', year: 'numeric' });
}

function inputDate(d) {
  if (!d) return '';
  const x = new Date(d);
  return `${x.getFullYear()}-${String(x.getMonth() + 1).padStart(2, '0')}-${String(x.getDate()).padStart(2, '0')}`;
}

// Generate every YYYY-MM-DD key in [start, end] inclusive. Untuk index task
// di calendar grid yang span beberapa hari.
function dateRangeKeys(start, end) {
  if (!start && !end) return [];
  // Effective single-day kalau hanya satu sisi terisi.
  const a = start ? new Date(start) : new Date(end);
  const b = end ? new Date(end) : new Date(start);
  a.setHours(0, 0, 0, 0);
  b.setHours(0, 0, 0, 0);
  const keys = [];
  const cur = new Date(a);
  while (cur <= b) {
    keys.push(dateKey(cur));
    cur.setDate(cur.getDate() + 1);
    if (keys.length > 90) break; // safety cap
  }
  return keys;
}

// Apakah task aktif di tanggal d? (start≤d≤end). Single-day kalau hanya satu sisi.
function taskCoversDate(task, d) {
  if (!task.startDate && !task.dueDate) return false;
  const k = dateKey(d);
  return dateRangeKeys(task.startDate, task.dueDate).includes(k);
}

function TimelineView() {
  const [campaigns, setCampaigns] = useState_tl([]);
  const [campaignId, setCampaignId] = useState_tl('');
  const [tasks, setTasks] = useState_tl([]);
  const [loading, setLoading] = useState_tl(true);
  const [editing, setEditing] = useState_tl(null); // task object | 'new' | null
  const [error, setError] = useState_tl(null);
  const [busy, setBusy] = useState_tl(false);
  // Calendar anchor month (1st of month)
  const [calAnchor, setCalAnchor] = useState_tl(() => {
    const d = new Date(); d.setDate(1); d.setHours(0, 0, 0, 0); return d;
  });

  useEffect_tl(() => {
    window.api.listCampaigns()
      .then((r) => {
        const list = r.campaigns || [];
        setCampaigns(list);
        const pick = list.find((c) => c.status === 'active') || list[0];
        if (pick) setCampaignId(pick.id);
        else setLoading(false);
      })
      .catch(() => setLoading(false));
  }, []);

  const refresh = React.useCallback(() => {
    if (!campaignId) return;
    setLoading(true);
    window.api.listTimeline(campaignId)
      .then((r) => setTasks(r.tasks || []))
      .catch((e) => setError(e.message))
      .finally(() => setLoading(false));
  }, [campaignId]);

  useEffect_tl(() => { refresh(); }, [refresh]);

  const camp = campaigns.find((c) => c.id === campaignId);

  const toggleStatus = async (task) => {
    const nextStatus = task.status === 'done' ? 'pending'
      : task.status === 'pending' ? 'in_progress' : 'done';
    setBusy(true);
    try {
      const r = await window.api.updateTask(campaignId, task.id, { status: nextStatus });
      setTasks((prev) => prev.map((t) => (t.id === task.id ? r.task : t)));
    } catch (e) { setError(e.message); }
    finally { setBusy(false); }
  };

  const seedTemplate = async (force = false) => {
    if (!campaignId) return;
    setBusy(true); setError(null);
    try {
      const r = await window.api.seedTimelineTemplate(campaignId, force);
      setTasks(r.tasks || []);
    } catch (e) {
      if (e.status === 409 && window.confirm('Sudah ada tasks. Overwrite dengan template default?')) {
        return seedTemplate(true);
      }
      setError(e.message);
    } finally { setBusy(false); }
  };

  const removeTask = async (task) => {
    if (!window.confirm(`Hapus task "${task.title}"?`)) return;
    setBusy(true);
    try {
      await window.api.deleteTask(campaignId, task.id);
      setTasks((prev) => prev.filter((t) => t.id !== task.id));
    } catch (e) { setError(e.message); }
    finally { setBusy(false); }
  };

  const stats = {
    total: tasks.length,
    done: tasks.filter((t) => t.status === 'done').length,
    inProgress: tasks.filter((t) => t.status === 'in_progress').length,
    overdue: tasks.filter((t) => {
      if (t.status === 'done' || !t.dueDate) return false;
      return new Date(t.dueDate) < new Date();
    }).length,
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
      <TopBar
        title="Timeline & Kalender"
        subtitle={camp
          ? `Tracking workflow campaign "${camp.title}"`
          : 'Pilih campaign untuk lihat timeline-nya'}
        right={
          <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
            {campaigns.length > 0 && (
              <select
                className="select"
                value={campaignId}
                onChange={(e) => setCampaignId(e.target.value)}
                style={{ minWidth: 220, fontSize: 12.5, padding: '6px 10px' }}
              >
                {campaigns.map((c) => (
                  <option key={c.id} value={c.id}>{c.title}</option>
                ))}
              </select>
            )}
            {campaignId && tasks.length > 0 && (
              <a
                className="btn btn-soft"
                href={`/api/campaigns/${campaignId}/timeline-report`}
                target="_blank"
                rel="noopener"
                title="Export laporan PDF dengan AI analisa risiko & rekomendasi"
                style={{ padding: '6px 10px', fontSize: 12.5 }}
              >
                <I.Send size={13} /> Export PDF
              </a>
            )}
            {campaignId && (
              <button className="btn btn-soft" onClick={() => seedTemplate(false)} disabled={busy}>
                <I.Sparkle size={13} /> Load template
              </button>
            )}
            {campaignId && (
              <button className="btn btn-primary" onClick={() => setEditing('new')} disabled={busy}>
                <I.Plus size={13} /> Tambah task
              </button>
            )}
          </div>
        }
      />

      <div className="scroll" style={{ flex: 1, overflow: 'auto', padding: 20, background: 'var(--bg)' }}>

        {error && (
          <div style={{ padding: '10px 14px', background: 'var(--danger-soft)', color: 'var(--danger)', borderRadius: 8, marginBottom: 14, fontSize: 13 }}>
            {error}
          </div>
        )}

        {/* Empty state */}
        {!loading && campaigns.length === 0 && (
          <div className="card" style={{ padding: 40, textAlign: 'center', color: 'var(--ink-3)' }}>
            <div style={{ fontSize: 32, marginBottom: 10 }}>📅</div>
            <div style={{ fontSize: 15, fontWeight: 600, color: 'var(--ink)', marginBottom: 4 }}>
              Belum ada campaign
            </div>
            <div style={{ fontSize: 13, lineHeight: 1.55 }}>
              Buat campaign pertamamu — timeline workflow akan tersedia di sini.
            </div>
          </div>
        )}

        {!loading && campaignId && tasks.length === 0 && (
          <div className="card" style={{ padding: 32, textAlign: 'center' }}>
            <div style={{ fontSize: 28, marginBottom: 10 }}>🚀</div>
            <div style={{ fontSize: 15, fontWeight: 700, marginBottom: 4 }}>Timeline kosong</div>
            <div style={{ fontSize: 13, color: 'var(--ink-3)', marginBottom: 18, maxWidth: 460, margin: '0 auto 18px', lineHeight: 1.55 }}>
              Klik <b>Load template</b> untuk auto-generate workflow standar (9 tasks: setup
              → launch → promote → collect → analyze → present), atau <b>Tambah task</b>
              untuk bikin manual.
            </div>
            <div style={{ display: 'flex', gap: 8, justifyContent: 'center' }}>
              <button className="btn btn-primary" onClick={() => seedTemplate(false)} disabled={busy}>
                <I.Sparkle size={13} /> Load template
              </button>
              <button className="btn btn-ghost" onClick={() => setEditing('new')} disabled={busy}>
                <I.Plus size={13} /> Tambah task manual
              </button>
            </div>
          </div>
        )}

        {tasks.length > 0 && (
          <>
            {/* Stats */}
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10, marginBottom: 14 }}>
              {[
                { label: 'Total task',   val: stats.total,      color: 'var(--ink)' },
                { label: 'Done',         val: stats.done,       color: 'oklch(0.55 0.16 145)' },
                { label: 'In progress',  val: stats.inProgress, color: 'oklch(0.55 0.16 75)' },
                { label: 'Overdue',      val: stats.overdue,    color: 'var(--danger)' },
              ].map((s) => (
                <div key={s.label} className="card" style={{ padding: 14 }}>
                  <div style={{ fontSize: 10.5, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>
                    {s.label}
                  </div>
                  <div className="mono" style={{ fontSize: 24, fontWeight: 700, marginTop: 4, color: s.color }}>
                    {s.val}
                  </div>
                </div>
              ))}
            </div>

            {/* Task list */}
            <div className="card" style={{ padding: 0, marginBottom: 14, overflow: 'hidden' }}>
              <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)' }}>
                <div style={{ fontSize: 13, fontWeight: 600 }}>Daftar Task</div>
                <div style={{ fontSize: 11.5, color: 'var(--ink-3)', marginTop: 2 }}>
                  Klik checkbox untuk siklus status: pending → in_progress → done
                </div>
              </div>
              {tasks.map((task) => {
                const cat = CATEGORY_META[task.category] || CATEGORY_META.other;
                const overdue = task.dueDate && task.status !== 'done' && new Date(task.dueDate) < new Date();
                return (
                  <div key={task.id} style={{
                    padding: '12px 18px', borderBottom: '1px solid var(--line)',
                    display: 'grid', gridTemplateColumns: 'auto 1fr auto auto auto', gap: 12, alignItems: 'center',
                  }}>
                    <button
                      onClick={() => toggleStatus(task)}
                      title={`Status: ${task.status} (klik untuk ubah)`}
                      style={{
                        width: 22, height: 22, borderRadius: 6,
                        border: '2px solid ' + (task.status === 'done' ? 'oklch(0.55 0.16 145)' : task.status === 'in_progress' ? 'oklch(0.55 0.16 75)' : 'var(--line-2)'),
                        background: task.status === 'done' ? 'oklch(0.55 0.16 145)' : task.status === 'in_progress' ? 'oklch(0.96 0.05 75)' : 'var(--surface)',
                        color: 'white', display: 'grid', placeItems: 'center', cursor: 'pointer', fontSize: 12,
                      }}
                    >{task.status === 'done' ? '✓' : task.status === 'in_progress' ? '⋯' : ''}</button>
                    <div>
                      <div style={{ fontSize: 13.5, fontWeight: 500, color: task.status === 'done' ? 'var(--ink-3)' : 'var(--ink)', textDecoration: task.status === 'done' ? 'line-through' : 'none' }}>
                        {task.title}
                      </div>
                      {task.description && (
                        <div style={{ fontSize: 12, color: 'var(--ink-3)', marginTop: 2 }}>
                          {task.description}
                        </div>
                      )}
                    </div>
                    <span style={{ fontSize: 11, padding: '3px 8px', borderRadius: 999, background: cat.bg, color: cat.color, fontWeight: 600 }}>
                      {cat.emoji} {cat.label}
                    </span>
                    <span style={{
                      fontSize: 12, color: overdue ? 'var(--danger)' : 'var(--ink-3)',
                      fontWeight: overdue ? 600 : 500, minWidth: 140, textAlign: 'right',
                    }}>
                      {task.startDate && task.dueDate && dateKey(task.startDate) !== dateKey(task.dueDate) ? (
                        <>{fmtDate(task.startDate)}<br/><span style={{ color: 'var(--ink-4)', fontSize: 10 }}>s/d</span> {fmtDate(task.dueDate)}</>
                      ) : (
                        task.dueDate || task.startDate ? fmtDate(task.dueDate || task.startDate) : '—'
                      )}
                      {overdue && <span style={{ display: 'block', fontSize: 10, marginTop: 1 }}>overdue</span>}
                    </span>
                    <div style={{ display: 'flex', gap: 4 }}>
                      <button onClick={() => setEditing(task)} title="Edit" className="btn btn-ghost" style={{ padding: 4 }}>
                        <I.Edit size={12} />
                      </button>
                      <button onClick={() => removeTask(task)} title="Hapus" className="btn btn-ghost" style={{ padding: 4, color: 'var(--danger)' }}>
                        <I.Trash size={12} />
                      </button>
                    </div>
                  </div>
                );
              })}
            </div>

            {/* Calendar */}
            <CalendarMonth
              anchor={calAnchor}
              onPrev={() => { const d = new Date(calAnchor); d.setMonth(d.getMonth() - 1); setCalAnchor(d); }}
              onNext={() => { const d = new Date(calAnchor); d.setMonth(d.getMonth() + 1); setCalAnchor(d); }}
              onToday={() => { const d = new Date(); d.setDate(1); d.setHours(0,0,0,0); setCalAnchor(d); }}
              tasks={tasks}
              onTaskClick={(t) => setEditing(t)}
              onDateClick={(d) => setEditing({ __new: true, prefillDate: d })}
            />
          </>
        )}

        {/* Edit/Create modal */}
        {editing && (() => {
          const isNew = editing === 'new' || editing.__new;
          const initialTask = isNew
            ? (editing.__new ? { startDate: editing.prefillDate, dueDate: editing.prefillDate } : null)
            : editing;
          return (
            <TaskFormModal
              initial={initialTask}
              isNew={isNew}
              onClose={() => setEditing(null)}
              onSave={async (payload) => {
                setBusy(true);
                try {
                  if (isNew) {
                    const r = await window.api.createTask(campaignId, payload);
                    setTasks((prev) => [...prev, r.task].sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0)));
                  } else {
                    const r = await window.api.updateTask(campaignId, editing.id, payload);
                    setTasks((prev) => prev.map((t) => (t.id === editing.id ? r.task : t)));
                  }
                  setEditing(null);
                } catch (e) { setError(e.message); }
                finally { setBusy(false); }
              }}
            />
          );
        })()}
      </div>
    </div>
  );
}

// ─── Month calendar grid ─────────────────────────────────────────────
function CalendarMonth({ anchor, onPrev, onNext, onToday, tasks, onTaskClick, onDateClick }) {
  const year = anchor.getFullYear();
  const month = anchor.getMonth();

  // Day of week header (Indonesian short, Senin first)
  const dows = ['Sen', 'Sel', 'Rab', 'Kam', 'Jum', 'Sab', 'Min'];

  // Build 6-row grid (42 cells) starting from Monday before month-1.
  const firstOfMonth = new Date(year, month, 1);
  const offset = (firstOfMonth.getDay() + 6) % 7;
  const start = new Date(firstOfMonth);
  start.setDate(start.getDate() - offset);

  const cells = [];
  for (let i = 0; i < 42; i++) {
    const d = new Date(start);
    d.setDate(start.getDate() + i);
    cells.push(d);
  }

  // Index tasks by EVERY date di range [startDate, dueDate]. Single-day task
  // di-treat sebagai range 1 hari (start=due). Task tanpa kedua-nya di-skip.
  const byDate = {};
  for (const t of tasks) {
    const keys = dateRangeKeys(t.startDate, t.dueDate);
    for (const k of keys) {
      (byDate[k] = byDate[k] || []).push(t);
    }
  }

  const monthLabel = anchor.toLocaleDateString('id-ID', { month: 'long', year: 'numeric' });
  const todayKey = dateKey(new Date());

  return (
    <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{ fontSize: 13, fontWeight: 600, flex: 1 }}>📅 {monthLabel}</div>
        <button className="btn btn-ghost" onClick={onPrev} style={{ padding: '4px 8px' }}>
          <I.ChevronLeft size={14} />
        </button>
        <button className="btn btn-ghost" onClick={onToday} style={{ padding: '4px 12px', fontSize: 12 }}>
          Hari ini
        </button>
        <button className="btn btn-ghost" onClick={onNext} style={{ padding: '4px 8px' }}>
          <I.ChevronRight size={14} />
        </button>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', borderTop: '1px solid var(--line)' }}>
        {dows.map((d) => (
          <div key={d} style={{
            padding: '8px 10px', fontSize: 10.5, fontWeight: 700,
            color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.06em',
            background: 'var(--bg-2)', borderRight: '1px solid var(--line)',
          }}>{d}</div>
        ))}
        {cells.map((d, i) => {
          const k = dateKey(d);
          const inMonth = d.getMonth() === month;
          const isToday = k === todayKey;
          const dayTasks = byDate[k] || [];
          return (
            <div
              key={i}
              onClick={(e) => {
                // Klik area kosong cell → buka form dengan tanggal pre-filled.
                // Klik di task pill ditangani oleh button di dalamnya (stop propagation).
                if (onDateClick && inMonth) onDateClick(d);
              }}
              title={inMonth ? 'Klik untuk tambah task di tanggal ini' : ''}
              style={{
                minHeight: 96, padding: 6,
                borderRight: '1px solid var(--line)',
                borderTop: '1px solid var(--line)',
                background: inMonth ? 'var(--surface)' : 'var(--bg-2)',
                opacity: inMonth ? 1 : 0.5,
                position: 'relative',
                cursor: inMonth ? 'pointer' : 'default',
                transition: 'background 120ms',
              }}
              onMouseEnter={(e) => { if (inMonth) e.currentTarget.style.background = 'var(--bg-2)'; }}
              onMouseLeave={(e) => { if (inMonth) e.currentTarget.style.background = 'var(--surface)'; }}
            >
              <div style={{
                fontSize: 11, fontWeight: isToday ? 700 : 500,
                color: isToday ? 'var(--primary)' : 'var(--ink-2)',
                background: isToday ? 'var(--primary-50)' : 'transparent',
                width: isToday ? 22 : 'auto', height: isToday ? 22 : 'auto',
                borderRadius: '50%', display: isToday ? 'grid' : 'block', placeItems: 'center',
                marginBottom: 3,
              }}>{d.getDate()}</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                {dayTasks.slice(0, 3).map((t) => {
                  const cat = CATEGORY_META[t.category] || CATEGORY_META.other;
                  const done = t.status === 'done';
                  // Multi-day task: tiap cell tampil pill terpisah dengan
                  // label yang sama (bukan satu bar panjang). Konsisten,
                  // gampang di-scan saat cell dilihat individual.
                  const isMultiDay = t.startDate && t.dueDate
                    && dateKey(t.startDate) !== dateKey(t.dueDate);
                  return (
                    <button key={t.id}
                      onClick={(e) => { e.stopPropagation(); onTaskClick(t); }}
                      title={t.title + (isMultiDay ? ` (${fmtDate(t.startDate)} – ${fmtDate(t.dueDate)})` : '')}
                      style={{
                        textAlign: 'left', cursor: 'pointer', border: 'none',
                        padding: '2px 5px', borderRadius: 4,
                        background: cat.bg, color: cat.color,
                        fontSize: 10, fontWeight: 600,
                        whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
                        opacity: done ? 0.55 : 1, textDecoration: done ? 'line-through' : 'none',
                      }}
                    >
                      {cat.emoji} {t.title}
                    </button>
                  );
                })}
                {dayTasks.length > 3 && (
                  <span style={{ fontSize: 9.5, color: 'var(--ink-3)' }}>+{dayTasks.length - 3} lagi</span>
                )}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ─── Task form modal ─────────────────────────────────────────────────
function TaskFormModal({ initial, isNew, onClose, onSave }) {
  const [title, setTitle] = useState_tl(initial?.title ?? '');
  const [description, setDescription] = useState_tl(initial?.description ?? '');
  const [category, setCategory] = useState_tl(initial?.category ?? 'other');
  const [status, setStatus] = useState_tl(initial?.status ?? 'pending');
  const [start, setStart] = useState_tl(inputDate(initial?.startDate));
  const [due, setDue] = useState_tl(inputDate(initial?.dueDate));
  const [busy, setBusy] = useState_tl(false);

  const isMultiDay = start && due && start !== due;
  const dateRangeText = (() => {
    if (!start && !due) return '';
    if (start && due && start === due) return `1 hari · ${fmtDate(start)}`;
    if (isMultiDay) {
      const a = new Date(start), b = new Date(due);
      const days = Math.round((b - a) / 86400000) + 1;
      return `${days} hari · ${fmtDate(start)} – ${fmtDate(due)}`;
    }
    return start ? `Mulai ${fmtDate(start)}` : `Deadline ${fmtDate(due)}`;
  })();

  const submit = async () => {
    if (!title.trim()) return;
    setBusy(true);
    await onSave({
      title: title.trim(),
      description: description.trim() || null,
      category,
      status,
      startDate: start ? new Date(start + 'T09:00:00').toISOString() : null,
      dueDate: due ? new Date(due + 'T17:00:00').toISOString() : null,
    });
    setBusy(false);
  };

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, background: 'rgba(15,18,30,0.5)',
      display: 'grid', placeItems: 'center', zIndex: 50, padding: 24,
    }}>
      <div onClick={(e) => e.stopPropagation()} className="card" style={{ width: '100%', maxWidth: 520, padding: 22 }}>
        <div style={{ fontSize: 15, fontWeight: 600, marginBottom: 14 }}>
          {isNew ? 'Tambah task baru' : 'Edit task'}
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <div>
            <label className="label">Judul</label>
            <input className="input" value={title} onChange={(e) => setTitle(e.target.value)} placeholder="cth. Sebar via WhatsApp Broadcast" autoFocus />
          </div>
          <div>
            <label className="label">Deskripsi <span style={{ color: 'var(--ink-4)', fontWeight: 400 }}>(opsional)</span></label>
            <textarea className="textarea" rows={2} value={description} onChange={(e) => setDescription(e.target.value)} placeholder="Detail eksekusi, channel, segmen target…" />
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <div>
              <label className="label">Kategori</label>
              <select className="select" value={category} onChange={(e) => setCategory(e.target.value)}>
                {Object.entries(CATEGORY_META).map(([id, c]) => (
                  <option key={id} value={id}>{c.emoji} {c.label}</option>
                ))}
              </select>
            </div>
            <div>
              <label className="label">Status</label>
              <select className="select" value={status} onChange={(e) => setStatus(e.target.value)}>
                <option value="pending">Pending</option>
                <option value="in_progress">In Progress</option>
                <option value="done">Done</option>
              </select>
            </div>
          </div>
          <div>
            <label className="label">Tanggal pengerjaan</label>
            <div style={{ display: 'grid', gridTemplateColumns: '1fr auto 1fr', gap: 8, alignItems: 'center' }}>
              <input
                className="input"
                type="date"
                value={start}
                onChange={(e) => {
                  setStart(e.target.value);
                  // Kalau due belum di-set / lebih awal, sync ke start.
                  if (!due || (e.target.value && due && e.target.value > due)) setDue(e.target.value);
                }}
                placeholder="mulai"
              />
              <span style={{ fontSize: 11, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>s/d</span>
              <input
                className="input"
                type="date"
                value={due}
                min={start || undefined}
                onChange={(e) => setDue(e.target.value)}
                placeholder="deadline"
              />
            </div>
            <div style={{ marginTop: 6, fontSize: 11.5, color: 'var(--ink-3)', minHeight: 16 }}>
              {dateRangeText || 'Kosongkan keduanya kalau task tanpa deadline. Set sama untuk single-day.'}
            </div>
          </div>
        </div>

        <div style={{ marginTop: 18, display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
          <button className="btn btn-ghost" onClick={onClose} disabled={busy}>Batal</button>
          <button className="btn btn-primary" onClick={submit} disabled={busy || !title.trim()}>
            {busy ? 'Menyimpan…' : (isNew ? 'Tambah task' : 'Simpan perubahan')}
          </button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { TimelineView });
