// JAVIS v2 — home layout (7-day strip + welcome hero + center composer)

const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ===== Seed events =====
function makeSeedEvents(today) {
  const td = isoDate(today);
  const tmrw = isoDate(addDays(today, 1));
  const yest = isoDate(addDays(today, -1));
  const wk3 = isoDate(addDays(today, 3));
  return [
  { id: "evt-seed-1", title: "팀 스탠드업", category: "업무",
    date: td, start: "10:00", end: "10:30",
    location: "회의실 3F", reminder: "10분 전" },
  { id: "evt-seed-2", title: "점심 — 민수랑", category: "식사",
    date: td, start: "12:30", end: "13:30",
    location: "성수동 라멘집", attendees: "민수" },
  { id: "evt-seed-3", title: "디자인 리뷰", category: "업무",
    date: td, start: "15:00", end: "16:00",
    location: "Zoom" },
  { id: "evt-seed-4", title: "요가", category: "운동",
    date: tmrw, start: "07:30", end: "08:30",
    location: "스튜디오 M" },
  { id: "evt-seed-5", title: "치과 진료", category: "개인",
    date: wk3, start: "14:00", end: "15:00",
    location: "한빛 치과", reminder: "1시간 전" },
  { id: "evt-seed-6", title: "조깅", category: "운동",
    date: yest, start: "18:00", end: "19:00" }];

}

const STORAGE_KEY = "javis.events.v3";
const HISTORY_KEY = "javis.history.v3";
const PROFILE_KEY = "javis.profile.v1";

function loadEvents(today) {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (raw) return JSON.parse(raw);
  } catch {}
  return makeSeedEvents(today);
}
function saveEvents(events) {try {localStorage.setItem(STORAGE_KEY, JSON.stringify(events));} catch {}}
function loadHistory() {
  try {const raw = localStorage.getItem(HISTORY_KEY);if (raw) return JSON.parse(raw);} catch {}
  return [];
}
function saveHistory(h) {try {localStorage.setItem(HISTORY_KEY, JSON.stringify(h.slice(-30)));} catch {}}
function loadProfile() {
  try {const raw = localStorage.getItem(PROFILE_KEY);if (raw) return JSON.parse(raw);} catch {}
  return { name: "이형진" };
}
function saveProfile(p) {try {localStorage.setItem(PROFILE_KEY, JSON.stringify(p));} catch {}}

// ===== Parser (reused) =====
async function parseInput(text, events, now) {
  const today = isoDate(now);
  const tmrw = isoDate(addDays(now, 1));
  const dow = DOW_KO[now.getDay()];
  const timeNow = `${String(now.getHours()).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`;

  const compactEvents = events.map((e) => ({ id: e.id, title: e.title, date: e.date, start: e.start, category: e.category }));

  const prompt = `You are JAVIS, a Korean natural-language schedule assistant.

Current date/time:
- Today: ${today} (${dow}요일)
- Now: ${timeNow}
- Tomorrow: ${tmrw}

Existing events (for delete/update intent matching):
${JSON.stringify(compactEvents, null, 0)}

User said: """${text}"""

Parse and respond with ONLY a JSON object (no prose, no markdown fences) matching this schema:
{
  "intent": "create" | "delete" | "update" | "query" | "unknown",
  "events": [
    {
      "title": "한국어 일정 제목 (간결, 5-15자)",
      "category": "운동" | "식사" | "업무" | "약속" | "개인" | "이동",
      "date": "YYYY-MM-DD",
      "start": "HH:MM" (24-hour),
      "end": "HH:MM" or null,
      "location": "장소" or null,
      "attendees": "사람 이름들" or null,
      "reminder": "10분 전" | "30분 전" | "1시간 전" | null
    }
  ],
  "target_ids": ["evt-..."],
  "updates": { "start": "HH:MM" | undefined, "date": "YYYY-MM-DD" | undefined, "title": "..." | undefined },
  "message": "사용자에게 보여줄 짧은 한국어 확인 메시지 (간결/프로페셔널, 예: '오후 2시 클라이밍 추가됨')",
  "query_dates": ["YYYY-MM-DD"]
}

Rules:
- create: extract EACH event into "events". One message can contain multiple events.
- 한국어 시간: "오후 2시"=14:00, "밤 11시"=23:00, "아침 7시"=07:00, "새벽 3시"=03:00, "정오"=12:00, "자정"=00:00.
- 한국어 날짜: "오늘"=today, "내일"=tomorrow, "모레"=day after, "다음주 월요일" 등. 미지정시 TODAY로.
- 자동 카테고리: 운동(클라이밍,요가,헬스,조깅,러닝,수영,등산,PT,필라테스,골프,테니스,축구,농구), 식사(점심,저녁,아침,식사,치킨,피자,회식,카페,커피,술,맥주,와인), 업무(회의,미팅,발표,보고,리뷰,데드라인,면접,출근), 약속(데이트,친구,모임,파티,약속,결혼식,생일), 개인(병원,진료,미용실,청소,빨래,쇼핑,은행,휴식), 이동(출장,비행,기차,이동,KTX,공항).
- delete (예: "클라이밍 취소해줘"): match existing events by title keyword, return ids in target_ids.
- update (예: "회의 4시로"): single id in target_ids + changes in updates.
- query (예: "오늘 일정 보여줘"): events:[], query_dates에 조회 날짜 배열 포함 (이번주 요약이면 7일 전체), message는 짧게.
- 메시지 톤: 간결/프로페셔널. 예: "오후 2시 '클라이밍' 추가됨", "2개 일정 추가됨", "'회의' 일정 오후 4시로 변경됨".

Output the JSON only.`;

  let resp;
  try {resp = await window.claude.complete(prompt);}
  catch (err) {return { intent: "unknown", events: [], message: `AI 오류: ${err.message}`, error: true };}

  let json = resp.trim();
  if (json.startsWith("```")) json = json.replace(/^```(?:json)?/i, "").replace(/```$/, "").trim();
  const f = json.indexOf("{"),l = json.lastIndexOf("}");
  if (f >= 0 && l > f) json = json.slice(f, l + 1);
  try {return JSON.parse(json);}
  catch {return { intent: "unknown", events: [], message: "응답 파싱에 실패했습니다. 다시 입력해 주세요.", error: true };}
}

// ===== Tweak defaults =====
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "userName": "이형진",
  "accent": "#7256FF",
  "weekStartsOnMonday": false
} /*EDITMODE-END*/;

const ACCENT_MAP = {
  "#7256FF": { deep: "#443399", soft: "rgba(114,86,255,0.15)" },
  "#A855F7": { deep: "#7E22CE", soft: "rgba(168,85,247,0.15)" },
  "#FF8800": { deep: "#A55D0A", soft: "rgba(255,136,0,0.15)"  },
  "#51BC51": { deep: "#136C13", soft: "rgba(81,188,81,0.15)"  }
};

// ===== Helpers =====
function initialOfName(name) {
  if (!name) return "?";
  const ch = name.trim().charAt(0);
  return ch || "?";
}

function buildWeek(now, startsMonday) {
  // Returns 7 Date objects for the week containing `now`.
  const d = new Date(now);
  d.setHours(0, 0, 0, 0);
  const day = d.getDay(); // 0=Sun
  const offset = startsMonday ?
  day === 0 ? -6 : 1 - day :
  -day;
  d.setDate(d.getDate() + offset);
  return Array.from({ length: 7 }, (_, i) => addDays(d, i));
}

// ===== Main App =====
const App = () => {
  const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS);

  const [now, setNow] = useState(() => new Date());
  useEffect(() => {
    const t = setInterval(() => setNow(new Date()), 60_000);
    return () => clearInterval(t);
  }, []);

  const [events, setEvents] = useState(() => loadEvents(now));
  useEffect(() => {saveEvents(events);}, [events]);

  const [input, setInput] = useState("");
  const [isThinking, setIsThinking] = useState(false);
  const [reply, setReply] = useState(null);
  const [history, setHistory] = useState(() => loadHistory());
  useEffect(() => {saveHistory(history);}, [history]);
  const [justAddedId, setJustAddedId] = useState(null);

  const [filter, setFilter] = useState("all"); // all / 업무 / 개인
  const [weekAnchor, setWeekAnchor] = useState(() => new Date());
  const [drawerDate, setDrawerDate] = useState(null);
  const [calendarOpen, setCalendarOpen] = useState(false);
  const [calAnchor, setCalAnchor] = useState(() => new Date());
  const [quickAddOpen, setQuickAddOpen] = useState(false);

  const userName = tweaks.userName || "이형진";
  const accent = tweaks.accent || "#1877F2";
  const weekStartsOnMonday = !!tweaks.weekStartsOnMonday;

  // accent css var
  useEffect(() => {
    const root = document.documentElement;
    const cfg = ACCENT_MAP[accent];
    if (cfg) {
      root.style.setProperty("--color-primary", accent);
      root.style.setProperty("--color-primary-deep", cfg.deep);
      root.style.setProperty("--color-primary-soft", cfg.soft);
    }
  }, [accent]);

  // Filter
  const filteredEvents = useMemo(() => {
    if (filter === "all") return events;
    if (filter === "업무") return events.filter((e) => e.category === "업무");
    if (filter === "개인") return events.filter((e) => ["개인", "약속", "식사", "운동", "이동"].includes(e.category));
    return events;
  }, [events, filter]);

  // Week
  const weekDays = useMemo(() => buildWeek(weekAnchor, weekStartsOnMonday), [weekAnchor, weekStartsOnMonday]);

  // Just-added clear
  useEffect(() => {
    if (!justAddedId) return;
    const t = setTimeout(() => setJustAddedId(null), 1500);
    return () => clearTimeout(t);
  }, [justAddedId]);

  // Auto-dismiss reply
  useEffect(() => {
    if (!reply || reply.persistent) return;
    const t = setTimeout(() => setReply(null), 6000);
    return () => clearTimeout(t);
  }, [reply]);

  const handleSubmit = useCallback(async (raw) => {
    const text = (raw ?? input).trim();
    if (!text) return;
    setInput("");
    setIsThinking(true);
    setReply({ thinking: true });
    setHistory((h) => [...h, { role: "user", text, ts: Date.now() }]);

    const result = await parseInput(text, events, new Date());
    setIsThinking(false);

    let msg = result.message || "처리됨";
    let isError = !!result.error;
    let lastId = null;

    if (result.intent === "create" && Array.isArray(result.events) && result.events.length > 0) {
      const newEvents = result.events.map((e, i) => ({
        id: `evt-${Date.now()}-${i}`,
        title: e.title || "(제목 없음)",
        category: CATEGORIES[e.category] ? e.category : "개인",
        date: e.date || isoDate(new Date()),
        start: e.start || "09:00",
        end: e.end || null,
        location: e.location || null,
        attendees: e.attendees || null,
        reminder: e.reminder || null
      }));
      setEvents((prev) => [...prev, ...newEvents]);
      lastId = newEvents[newEvents.length - 1].id;
      // jump week if outside view
      const firstDate = new Date(newEvents[0].date + "T00:00");
      const wkStart = weekDays[0];
      const wkEnd = addDays(wkStart, 6);
      if (firstDate < wkStart || firstDate > wkEnd) {
        setWeekAnchor(firstDate);
      }
    } else if (result.intent === "delete" && Array.isArray(result.target_ids) && result.target_ids.length > 0) {
      const set = new Set(result.target_ids);
      setEvents((prev) => prev.filter((e) => !set.has(e.id)));
    } else if (result.intent === "update" && Array.isArray(result.target_ids) && result.target_ids.length > 0 && result.updates) {
      const set = new Set(result.target_ids);
      setEvents((prev) => prev.map((e) => set.has(e.id) ? { ...e, ...result.updates } : e));
      lastId = result.target_ids[0];
    }

    if (result.intent === "query") {
      const qDates = new Set(result.query_dates || []);
      const queryEvents = qDates.size > 0
        ? [...events].filter(e => qDates.has(e.date)).sort((a, b) => a.date.localeCompare(b.date) || hhmmToMins(a.start) - hhmmToMins(b.start))
        : [];
      setReply({ msg, queryEvents: queryEvents.length > 0 ? queryEvents : null, persistent: true, error: isError });
    } else {
      setReply({ msg, error: isError });
    }
    setHistory((h) => [...h, { role: "bot", text: msg, ts: Date.now() }]);
    if (lastId) setJustAddedId(lastId);
  }, [input, events, weekDays]);

  const handleDelete = useCallback((id) => {
    const ev = events.find((e) => e.id === id);
    setEvents((prev) => prev.filter((e) => e.id !== id));
    if (ev) setReply({ msg: `'${ev.title}' 일정 삭제됨` });
  }, [events]);

  function weekShift(n) {setWeekAnchor((a) => addDays(a, n * 7));}
  function goWeekToday() {setWeekAnchor(new Date());}

  function eventsForDate(dateIso) {
    return filteredEvents.
    filter((e) => e.date === dateIso).
    sort((a, b) => hhmmToMins(a.start) - hhmmToMins(b.start));
  }

  return (
    <div className="home">
      <div className="home-inner">

        {/* Top nav */}
        <header className="home-nav">
          <div className="wordmark">
            <span className="mark"><JIcon name="sparkles" size={16} color="currentColor" /></span>
            JAVIS
          </div>
          <BmButton variant="outline-neutral" size="icon-sm" title="프로필" className="!rounded-full">
            <span className="avatar">{initialOfName(userName)}</span>
          </BmButton>
        </header>

        {/* Toolbar */}
        <div className="home-toolbar">
          <div className="filter-pills">
            <BmChip className={filter === "all" ? "!bg-[#7256ff] !border-[#7256ff] !text-white hover:!bg-[#443399] hover:!border-[#443399]" : ""} onClick={() => setFilter("all")}>전체</BmChip>
            <BmChip className={filter === "업무" ? "!bg-[#7256ff] !border-[#7256ff] !text-white hover:!bg-[#443399] hover:!border-[#443399]" : ""} onClick={() => setFilter("업무")}>업무</BmChip>
            <BmChip className={filter === "개인" ? "!bg-[#7256ff] !border-[#7256ff] !text-white hover:!bg-[#443399] hover:!border-[#443399]" : ""} onClick={() => setFilter("개인")}>개인</BmChip>
          </div>
          <div className="toolbar-actions">
            <BmButton variant="outline-neutral" size="icon-sm" onClick={() => weekShift(-1)} title="지난 주">
              <JIcon name="chevron-left" size={16} />
            </BmButton>
            <BmButton variant="outline-neutral" size="sm" onClick={goWeekToday}>이번 주</BmButton>
            <BmButton variant="outline-neutral" size="icon-sm" onClick={() => weekShift(1)} title="다음 주">
              <JIcon name="chevron-right" size={16} />
            </BmButton>
            <BmButton variant="primary" size="sm" onClick={() => setQuickAddOpen(true)}>
              <JIcon name="plus" size={15} color="currentColor" /> 할일
            </BmButton>
            <BmButton variant="outline-neutral" size="sm" onClick={() => {setCalAnchor(weekAnchor);setCalendarOpen(true);}}>
              <JIcon name="calendar" size={15} /> 캘린더 보기
            </BmButton>
          </div>
        </div>

        {/* 7-day strip */}
        <div className="week-strip">
          {weekDays.map((d) => {
            const dow = d.getDay();
            const isToday = sameDay(d, now);
            const evs = eventsForDate(isoDate(d));
            return (
              <button
                key={isoDate(d)}
                className={`day-card ${isToday ? "is-today" : ""}`}
                onClick={() => setDrawerDate(isoDate(d))} style={{ padding: "14px 14px 16px", height: "241px" }}>
                
                <div className="d-head">
                  <span className={`d-dow ${dow === 0 ? "is-sun" : ""} ${dow === 6 ? "is-sat" : ""}`}>{DOW_KO[dow]}</span>
                  <span className="d-num">{d.getDate()}</span>
                </div>
                <div className="d-events">
                  {evs.length === 0 &&
                  <div className="d-empty">—</div>
                  }
                  {evs.slice(0, 3).map((ev) => {
                    const c = catLookup(ev.category);
                    const nowMins = now.getHours() * 60 + now.getMinutes();
                    const startMins = hhmmToMins(ev.start);
                    const endMins = ev.end ? hhmmToMins(ev.end) : startMins + 60;
                    const isNow = isToday && startMins <= nowMins && nowMins < endMins;
                    return (
                      <div key={ev.id} className={`d-evt ${isNow ? "is-now" : ""}`}
                      style={{ "--cat-color": c.color, "--cat-bg": c.bg }}>
                        <span className="d-evt-time">{fmtTimeShort(ev.start)}</span>
                        <span className="d-evt-title">{ev.title}</span>
                        {isNow && <span className="d-evt-now">진행 중</span>}
                      </div>);

                  })}
                  {evs.length > 3 && <div className="d-more">+{evs.length - 3}건 더</div>}
                </div>
              </button>);

          })}
        </div>

        {/* Hero */}
        <section className="hero">
          <h1>안녕하세요, {userName}님</h1>
          <p className="sub">오늘은 어떻게 도와드릴까요?</p>

          {reply &&
          <div className={`ai-reply ${reply.error ? "error" : ""} ${reply.queryEvents ? "has-events" : ""}`}>
            <div className="ai-reply-row">
              <JIcon name={reply.error ? "info" : "check-circle"} size={18} color={reply.error ? "var(--color-critical)" : "#fff"} />
              <span className="ai-text">
                {reply.thinking ?
                <span className="thinking-row">
                  JAVIS가 일정을 정리하고 있어요
                  <span className="thinking-dot" /><span className="thinking-dot" /><span className="thinking-dot" />
                </span> :
                reply.msg}
              </span>
              {!reply.thinking &&
              <BmButton variant="outline-neutral-ghost" size="icon-xs" className="!rounded-full" onClick={() => setReply(null)}>
                <JIcon name="x" size={14} />
              </BmButton>}
            </div>
            {reply.queryEvents && reply.queryEvents.length > 0 && (() => {
              const DOW = ["일","월","화","수","목","금","토"];
              const groups = [];
              const seen = new Map();
              reply.queryEvents.forEach(ev => {
                if (!seen.has(ev.date)) { seen.set(ev.date, []); groups.push(ev.date); }
                seen.get(ev.date).push(ev);
              });
              return (
                <div className="reply-event-list">
                  {groups.map(date => {
                    const d = new Date(date);
                    const label = `${DOW[d.getDay()]}요일 ${d.getMonth()+1}/${d.getDate()}`;
                    return (
                      <div key={date} className="reply-day-group">
                        <span className="reply-day-label">{label}</span>
                        {seen.get(date).map(ev => {
                          const c = catLookup(ev.category);
                          return (
                            <div key={ev.id} className="reply-evt" style={{"--cat-color": c.color}}>
                              <span className="reply-evt-time">{ev.start}</span>
                              <span className="reply-evt-title">{ev.title}</span>
                            </div>
                          );
                        })}
                      </div>
                    );
                  })}
                </div>
              );
            })()}
          </div>
          }

          <HeroComposer
            value={input}
            onChange={setInput}
            onSubmit={handleSubmit}
            isThinking={isThinking} />
          

          <div className="quick-actions">
            <BmChip onClick={() => handleSubmit("오늘 일정 보여줘")}>오늘 일정 보여줘</BmChip>
            <BmChip onClick={() => handleSubmit("내일 오후 3시 팀 회의 추가")}>내일 오후 3시 팀 회의 추가</BmChip>
            <BmChip onClick={() => handleSubmit("이번 주 일정 요약해줘")}>이번 주 일정 요약</BmChip>
            <BmChip onClick={() => handleSubmit("오늘 저녁 7시 친구랑 강남에서 저녁식사")}>오늘 저녁 7시 친구랑 강남에서 저녁식사</BmChip>
          </div>
        </section>

        {/* Day drawer */}
        {drawerDate &&
        <DayDrawer
          dateIso={drawerDate}
          now={now}
          events={eventsForDate(drawerDate)}
          justAddedId={justAddedId}
          onClose={() => setDrawerDate(null)}
          onDelete={handleDelete} />

        }

        {/* Calendar overlay (month/week) */}
        {calendarOpen &&
        <CalendarOverlay
          events={filteredEvents}
          anchor={calAnchor}
          setAnchor={setCalAnchor}
          today={now}
          justAddedId={justAddedId}
          onClose={() => setCalendarOpen(false)}
          onDelete={handleDelete}
          onPickDate={(iso) => {setDrawerDate(iso);}} />

        }

        {/* Quick add modal */}
        {quickAddOpen &&
        <QuickAddModal
          today={now}
          onClose={() => setQuickAddOpen(false)}
          onAdd={(ev) => {
            const full = { id: `evt-${Date.now()}`, ...ev };
            setEvents((prev) => [...prev, full]);
            setJustAddedId(full.id);
            setReply({ msg: `'${full.title}' 추가됨` });
            setQuickAddOpen(false);
            const d = new Date(full.date + "T00:00");
            const wkStart = weekDays[0],wkEnd = addDays(wkStart, 6);
            if (d < wkStart || d > wkEnd) setWeekAnchor(d);
          }} />

        }
      </div>

      {/* ===== Tweaks ===== */}
      {window.TweaksPanel &&
      <window.TweaksPanel title="Tweaks">
          <window.TweakSection label="프로필">
            <window.TweakText
            label="이름"
            value={userName}
            onChange={(v) => setTweak("userName", v)} />
          
          </window.TweakSection>
          <window.TweakSection label="레이아웃">
            <window.TweakRadio
            label="주 시작"
            value={weekStartsOnMonday ? "mon" : "sun"}
            onChange={(v) => setTweak("weekStartsOnMonday", v === "mon")}
            options={[
            { value: "sun", label: "일요일" },
            { value: "mon", label: "월요일" }]
            } />
          
          </window.TweakSection>
          <window.TweakSection label="컬러 액센트">
            <window.TweakColor
            label="포인트"
            value={accent}
            onChange={(v) => setTweak("accent", v)}
            options={["#7256FF", "#A855F7", "#FF8800", "#51BC51"]} />
          
          </window.TweakSection>
          <window.TweakSection label="데이터">
            <window.TweakButton
            label="시연용 일정으로 초기화"
            onClick={() => {
              if (confirm("저장된 모든 일정을 시연용 데이터로 되돌릴까요?")) {
                setEvents(makeSeedEvents(new Date()));
                setHistory([]);
                setReply({ msg: "시연용 일정으로 초기화됨" });
              }
            }} />
          
            <window.TweakButton
            label="모든 일정 삭제"
            secondary
            onClick={() => {
              if (confirm("모든 일정을 삭제할까요?")) {
                setEvents([]);
                setReply({ msg: "모든 일정이 삭제되었습니다" });
              }
            }} />
          
          </window.TweakSection>
        </window.TweaksPanel>
      }
    </div>);

};

// ===== Hero composer =====
const HeroComposer = ({ value, onChange, onSubmit, isThinking }) => {
  const taRef = useRef(null);
  useEffect(() => {
    const ta = taRef.current;
    if (!ta) return;
    ta.style.height = "auto";
    ta.style.height = Math.min(160, ta.scrollHeight) + "px";
  }, [value]);

  function handleKey(e) {
    if (e.key === "Enter" && !e.shiftKey && !e.isComposing && e.keyCode !== 229) {
      e.preventDefault();
      if (!isThinking && value.trim()) onSubmit();
    }
  }
  const canSend = !isThinking && value.trim().length > 0;

  return (
    <div className="hero-composer" style={{ flexDirection: "row", alignItems: "center" }}>
      <textarea
        ref={taRef}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        onKeyDown={handleKey}
        rows={1}
        placeholder="예: 내일 오후 3시 팀 회의"
        disabled={isThinking} />
      
      <button className="hero-send-btn" onClick={() => onSubmit()} disabled={!canSend} title="전송 (Enter)">
        {isThinking ?
        <span style={{ display: "inline-flex", color: "#fff" }}>
            <span className="thinking-dot" /><span className="thinking-dot" /><span className="thinking-dot" />
          </span> :
        <JIcon name="arrow-up" size={18} color="currentColor" />}
      </button>
    </div>);

};

// ===== Day drawer =====
const DayDrawer = ({ dateIso, events, now, justAddedId, onClose, onDelete }) => {
  // close on Esc
  useEffect(() => {
    const fn = (e) => {if (e.key === "Escape") onClose();};
    window.addEventListener("keydown", fn);
    return () => window.removeEventListener("keydown", fn);
  }, [onClose]);

  const d = new Date(dateIso + "T00:00");
  const isToday = sameDay(d, now);
  const nowMins = now.getHours() * 60 + now.getMinutes();

  return (
    <>
      <div className="scrim" onClick={onClose} />
      <div className="drawer">
        <div className="dr-head">
          <div className="dr-title-block">
            <div className="dr-eyebrow">{isToday ? "오늘" : DOW_KO[d.getDay()] + "요일"}</div>
            <div className="dr-title">{fmtDateKR(d)}</div>
          </div>
          <BmButton variant="outline-neutral-ghost" size="icon-sm" className="!rounded-full" onClick={onClose}><JIcon name="x" size={16} /></BmButton>
        </div>
        <div className="dr-body">
          {events.length === 0 ?
          <div className="dr-empty">
              <div className="e-icon"><JIcon name="calendar" size={24} /></div>
              <h4>일정 없음</h4>
              <p>이 날에는 등록된 일정이 없습니다.</p>
            </div> :

          events.map((ev) => {
            const c = catLookup(ev.category);
            const start = hhmmToMins(ev.start);
            const end = ev.end ? hhmmToMins(ev.end) : start + 60;
            const past = isToday && end < nowMins;
            const isNow = isToday && start <= nowMins && nowMins < end;
            return (
              <div
                key={ev.id}
                className={`event-card ${past ? "is-past" : ""} ${isNow ? "is-now" : ""} ${ev.id === justAddedId ? "is-just-added" : ""}`}
                style={{ "--cat-color": c.color, "--cat-bg": c.bg, "--cat-fg": c.fg }}>
                
                  <div className="ec-top">
                    <span className="ec-time">{fmtTime12(ev.start)}{ev.end ? ` – ${fmtTime12(ev.end)}` : ""}</span>
                    <span className="ec-title-inline">{ev.title}</span>
                    {isNow && <span className="ec-now-badge">진행 중</span>}
                    <BmButton variant="outline-danger" size="icon-xs" className="ml-auto" title="삭제" onClick={() => onDelete(ev.id)}>
                      <JIcon name="trash" size={14} />
                    </BmButton>
                  </div>
                  <div className="ec-bottom">
                    <span className="ec-cat">{c.label}</span>
                    {ev.location && <span className="ec-meta-item"><JIcon name="map-pin" size={14} />{ev.location}</span>}
                    {ev.attendees && <span className="ec-meta-item"><JIcon name="users" size={14} />{ev.attendees}</span>}
                    {ev.reminder && <span className="ec-meta-item bell"><JIcon name="bell" size={14} />{ev.reminder}</span>}
                  </div>
                </div>);

          })
          }
        </div>
      </div>
    </>);

};

// ===== Calendar modal =====
const CalendarOverlay = ({ events, anchor, setAnchor, today, justAddedId, onClose, onDelete, onPickDate }) => {
  useEffect(() => {
    const fn = (e) => {if (e.key === "Escape") onClose();};
    window.addEventListener("keydown", fn);
    return () => window.removeEventListener("keydown", fn);
  }, [onClose]);

  function shift(n) {
    setAnchor(new Date(anchor.getFullYear(), anchor.getMonth() + n, 1));
  }

  return (
    <div className="cal-modal-wrap" onClick={(e) => {if (e.target === e.currentTarget) onClose();}}>
      <div className="cal-modal" role="dialog" aria-modal="true" aria-label="캘린더">
        <div className="cal-head">
          <div className="cal-nav">
            <BmButton variant="outline-neutral" size="icon-sm" onClick={() => shift(-1)} title="이전">
              <JIcon name="chevron-left" size={16} />
            </BmButton>
            <BmButton variant="outline-neutral" size="sm" onClick={() => setAnchor(new Date())}>오늘</BmButton>
            <BmButton variant="outline-neutral" size="icon-sm" onClick={() => shift(1)} title="다음">
              <JIcon name="chevron-right" size={16} />
            </BmButton>
          </div>
          <div className="cal-title">{fmtMonthKR(anchor)}</div>
          <div style={{ flex: 1 }} />
          <BmButton variant="outline-neutral-ghost" size="icon-sm" onClick={onClose}>
            <JIcon name="x" size={16} />
          </BmButton>
        </div>
        <div className="cal-body">
          <MonthView events={events} anchor={anchor} today={today} onDelete={onDelete} />
        </div>
      </div>
    </div>);

};

// ===== Quick add modal =====
const QuickAddModal = ({ today, onClose, onAdd }) => {
  const [form, setForm] = useState({
    title: "",
    category: "업무",
    date: isoDate(today),
    start: "09:00",
    end: "",
    location: "",
    reminder: ""
  });
  useEffect(() => {
    const fn = (e) => {if (e.key === "Escape") onClose();};
    window.addEventListener("keydown", fn);
    return () => window.removeEventListener("keydown", fn);
  }, [onClose]);

  function update(k, v) {setForm((f) => ({ ...f, [k]: v }));}
  function submit() {
    if (!form.title.trim()) return;
    onAdd({
      title: form.title.trim(),
      category: form.category,
      date: form.date,
      start: form.start,
      end: form.end || null,
      location: form.location.trim() || null,
      reminder: form.reminder || null
    });
  }

  return (
    <>
      <div className="scrim" onClick={onClose} />
      <div className="drawer">
        <div className="dr-head">
          <div className="dr-title-block">
            <div className="dr-eyebrow">새 일정</div>
            <div className="dr-title">직접 추가</div>
          </div>
          <BmButton variant="outline-neutral-ghost" size="icon-sm" className="!rounded-full" onClick={onClose}><JIcon name="x" size={16} /></BmButton>
        </div>
        <div className="dr-body">
          <div className="quick-add-form">
            <div className="qf-row">
              <label className="qf-lbl">제목</label>
              <BmInput
                value={form.title}
                onChange={(e) => update("title", e.target.value)}
                placeholder="예: 디자인 리뷰 미팅"
                autoFocus />
            </div>
            <div className="qf-row">
              <label className="qf-lbl">카테고리</label>
              <div className="qf-cat-row">
                {CAT_KEYS.map((k) =>
                <BmChip
                  key={k}
                  className={form.category === k ? "!bg-[#7256ff] !border-[#7256ff] !text-white hover:!bg-[#443399] hover:!border-[#443399]" : ""}
                  onClick={() => update("category", k)}>
                  {k}</BmChip>
                )}
              </div>
            </div>
            <div className="qf-row">
              <label className="qf-lbl">날짜 & 시간</label>
              <div className="qf-row-h">
                <BmInput type="date" value={form.date} onChange={(e) => update("date", e.target.value)} />
                <BmInput type="time" value={form.start} onChange={(e) => update("start", e.target.value)} wrapperClassName="max-w-[120px]" />
                <BmInput type="time" value={form.end} onChange={(e) => update("end", e.target.value)} wrapperClassName="max-w-[120px]" />
              </div>
            </div>
            <div className="qf-row">
              <label className="qf-lbl">장소 (선택)</label>
              <BmInput value={form.location} onChange={(e) => update("location", e.target.value)} placeholder="예: 회의실 3F" />
            </div>
            <div className="qf-row">
              <label className="qf-lbl">알림 (선택)</label>
              <div className="qf-cat-row">
                {["", "10분 전", "30분 전", "1시간 전"].map((r) =>
                <BmChip
                  key={r || "none"}
                  className={form.reminder === r ? "!bg-[#7256ff] !border-[#7256ff] !text-white hover:!bg-[#443399] hover:!border-[#443399]" : ""}
                  onClick={() => update("reminder", r)}>
                  {r || "없음"}</BmChip>
                )}
              </div>
            </div>
            <div className="qf-actions">
              <BmButton variant="outline-neutral-ghost" size="sm" onClick={onClose}>취소</BmButton>
              <BmButton variant="primary" size="sm" onClick={submit} disabled={!form.title.trim()}>
                <JIcon name="plus" size={14} color="currentColor" /> 추가
              </BmButton>
            </div>
          </div>
        </div>
      </div>
    </>);

};

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