/* ================ MAIN APP ================ */

const wandeeDefaults = /*EDITMODE-BEGIN*/{
  "accent": "#3b6ef5",
  "theme": "light",
  "density": "comfortable",
  "aiPosition": "right",
  "kpiLayout": "horizontal",
  "showAiHints": true
}/*EDITMODE-END*/;

// ── DB Status Indicator ──────────────────────────────────────
const DbStatus = ({ status }) => {
  const cfg = {
    loading:   { color: "var(--ink-faint)",  dot: "#94a3b8", label: "กำลังเชื่อมต่อ..." },
    live:      { color: "var(--success)",    dot: "#16a34a", label: "Live · Supabase" },
    mock:      { color: "var(--warning)",    dot: "#ea7c0c", label: "Demo data" },
    error:     { color: "var(--danger)",     dot: "#dc2626", label: "ไม่สามารถเชื่อมต่อได้" },
  }[status] ?? { color: "var(--ink-faint)", dot: "#94a3b8", label: "" };

  return (
    <div style={{ display: "flex", alignItems: "center", gap: 5, fontSize: 11, color: cfg.color, fontFamily: "var(--mono)" }}>
      <span style={{
        width: 6, height: 6, borderRadius: "50%",
        background: cfg.dot,
        boxShadow: status === "live" ? `0 0 0 2px ${cfg.dot}33` : "none",
      }} />
      {cfg.label}
    </div>
  );
};

// ── Sync Panel ───────────────────────────────────────────────
const SUPABASE_FUNC_URL = 'https://uaykdkaraisttedteirb.supabase.co/functions/v1';
const SYNC_SECRET       = 'wandee2026';
const SYNC_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InVheWtka2FyYWlzdHRlZHRlaXJiIiwicm9sZSI6ImFub24iLCJpYXQiOjE3Nzg1NzU1ODksImV4cCI6MjA5NDE1MTU4OX0.0ggs_N17TiO49R1z9qwKIUkyp_V9oB3bugecyQluOGc';

const AD_ACCOUNTS = [
  { id: '729603149949974', name: 'Wandee Shop', enabled: true },
  { id: '162026164',       name: 'เพจ Wandee Luxury Style', enabled: true },
];

const SyncPanel = ({ onClose, onSyncDone, activeAccId }) => {
  const today = new Date().toLocaleDateString('en-CA');
  const ymdAgo = (n) => { const d = new Date(); d.setDate(d.getDate() - n); return d.toLocaleDateString('en-CA'); };
  // N-day window inclusive: 1 วัน = วันนี้, 3 วัน = วันนี้+2วันก่อน, …
  const ago1  = today;          // 1 day  = today only
  const ago3  = ymdAgo(2);      // 3 days = today + 2 prior
  const ago30 = ymdAgo(29);     // 30 days

  // default = 1 วัน (เร็วสุด — sync เฉพาะข้อมูลล่าสุด)
  const [since, setSince]       = React.useState(ago1);
  const [until, setUntil]       = React.useState(today);
  // ถ้ามี activeAccId → preselect แค่ตัวนั้น; ถ้าไม่ → preselect ทุก account ที่ enabled
  const [selAccs, setSelAccs]   = React.useState(() =>
    activeAccId ? [activeAccId] : AD_ACCOUNTS.filter(a => a.enabled).map(a => a.id)
  );
  const [phase, setPhase]       = React.useState('idle'); // idle | running | done | error
  const [result, setResult]     = React.useState(null);
  const [errMsg, setErrMsg]     = React.useState('');
  const [needToken, setNeedToken] = React.useState(false);

  // เคลียร์ผลเก่าเมื่อ user เปลี่ยน date / account → กัน confusion ว่า "ฉัน sync ใหม่หรือยัง"
  // (ใช้ ref กัน reset ตอน mount ครั้งแรก)
  const isFirstRun = React.useRef(true);
  React.useEffect(() => {
    if (isFirstRun.current) { isFirstRun.current = false; return; }
    if (phase === 'done' || phase === 'error') {
      setPhase('idle');
      setResult(null);
      setErrMsg('');
      setNeedToken(false);
    }
  }, [since, until, selAccs.join(',')]);

  const toggleAcc = (id) => setSelAccs(prev =>
    prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]
  );

  // helper: แปลง error อะไรก็ได้ → string ที่อ่านออก
  const errToStr = (e) => {
    if (!e) return '';
    if (typeof e === 'string') return e;
    if (e instanceof Error) return e.message;
    if (typeof e === 'object') {
      // Facebook API error shape: { message, type, code, error_subcode }
      if (e.message) return typeof e.message === 'string' ? e.message : JSON.stringify(e.message);
      if (e.error)   return errToStr(e.error);
      try { return JSON.stringify(e); } catch { return String(e); }
    }
    return String(e);
  };

  const runSync = async () => {
    if (!selAccs.length) return;
    setPhase('running'); setResult(null); setErrMsg(''); setNeedToken(false);
    try {
      const res = await fetch(`${SUPABASE_FUNC_URL}/fb-sync`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${SYNC_ANON_KEY}`,
          'x-sync-secret': SYNC_SECRET,
        },
        body: JSON.stringify({ account_ids: selAccs, since, until }),
      });
      const data = await res.json().catch(() => ({}));
      console.log('[fb-sync] HTTP', res.status, 'response:', data);
      const topErr = errToStr(data.error);
      if (topErr.includes('FB_ACCESS_TOKEN')) { setNeedToken(true); setPhase('error'); return; }
      if (!res.ok || !data.ok) throw new Error(topErr || `HTTP ${res.status}`);

      // ตรวจ per-account error (เช่น token หมดอายุ)
      const accErrors = Object.entries(data.results || {})
        .filter(([, r]) => r?.error)
        .map(([id, r]) => ({ id, msg: errToStr(r.error) }));
      if (accErrors.length === Object.keys(data.results || {}).length && accErrors.length > 0) {
        const firstErr = accErrors[0].msg || '';
        if (/access token|OAuthException|Session has expired|code["']?:\s*190/i.test(firstErr)) {
          setNeedToken(true); setPhase('error'); return;
        }
        setPhase('error'); setErrMsg(firstErr); return;
      }
      setPhase('done'); setResult(data.results);
      onSyncDone?.();
    } catch (err) {
      const msg = errToStr(err);
      if (/fetch|network/i.test(msg)) {
        setNeedToken(true); setPhase('error');
      } else {
        setPhase('error'); setErrMsg(msg);
      }
    }
  };

  const presetRanges = [
    { l: '1 วัน',  since: ago1 },
    { l: '3 วัน',  since: ago3 },
    { l: '7 วัน',  since: ymdAgo(6) },
    { l: '30 วัน', since: ago30 },
    { l: '90 วัน', since: ymdAgo(89) },
  ];

  // Custom range popup state (เหมือน Overview)
  const [showCustom, setShowCustom] = React.useState(false);
  // ถือว่า "custom" = since ไม่ตรงกับ preset ไหนเลย
  const isPreset = presetRanges.some(p => p.since === since) && until === today;
  const fmtTh = (s) => new Date(s + 'T00:00:00').toLocaleDateString('th-TH', { day: 'numeric', month: 'short' });

  const labelStyle = { fontSize: 11, fontWeight: 600, color: 'var(--ink-faint)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 6 };
  const inputStyle = { width: '100%', padding: '6px 8px', border: '1px solid var(--border)', borderRadius: 6, fontSize: 13, background: 'var(--bg-elevated)', color: 'var(--ink)', boxSizing: 'border-box' };

  return (
    <div style={{ position: 'fixed', inset: 0, zIndex: 900, display: 'flex', alignItems: 'stretch', justifyContent: 'flex-end' }}
      onClick={e => e.target === e.currentTarget && onClose()}>

      {/* Backdrop */}
      <div style={{ position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.25)' }} onClick={onClose} />

      {/* Panel */}
      <div style={{ position: 'relative', zIndex: 1, width: 340, background: 'var(--bg)', borderLeft: '1px solid var(--border)', display: 'flex', flexDirection: 'column', boxShadow: '-4px 0 24px rgba(0,0,0,.12)' }}>

        {/* Header */}
        <div style={{ padding: '16px 20px', borderBottom: '1px solid var(--border)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div>
            <div style={{ fontWeight: 600, fontSize: 15 }}>Sync Facebook Ads</div>
            <div style={{ fontSize: 11, color: 'var(--ink-faint)', marginTop: 2 }}>ดึงข้อมูลจาก Facebook เข้า Supabase</div>
          </div>
          <button className="icon-btn" onClick={onClose}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M18 6L6 18M6 6L18 18"/></svg>
          </button>
        </div>

        {/* Body */}
        <div style={{ flex: 1, overflowY: 'auto', padding: '20px' }}>

          {/* Accounts */}
          <div style={{ marginBottom: 20 }}>
            <div style={labelStyle}>Ad Accounts</div>
            {AD_ACCOUNTS.map(acc => (
              <label key={acc.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 0', cursor: acc.enabled ? 'pointer' : 'not-allowed', opacity: acc.enabled ? 1 : 0.45 }}>
                <input type="checkbox" checked={selAccs.includes(acc.id)} disabled={!acc.enabled}
                  onChange={() => acc.enabled && toggleAcc(acc.id)}
                  style={{ accentColor: 'var(--accent)', width: 14, height: 14 }} />
                <div>
                  <div style={{ fontSize: 13, fontWeight: 500 }}>{acc.name}</div>
                  <div style={{ fontSize: 11, color: 'var(--ink-faint)' }}>{acc.id}{acc.note ? ` · ${acc.note}` : ''}</div>
                </div>
              </label>
            ))}
          </div>

          {/* Date Range — preset chips + custom modal (เหมือน Overview) */}
          <div style={{ marginBottom: 20 }}>
            <div style={labelStyle}>ช่วงวันที่</div>
            <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
              {presetRanges.map(p => {
                const active = since === p.since && until === today && !showCustom;
                return (
                  <button key={p.l} onClick={() => { setSince(p.since); setUntil(today); setShowCustom(false); }}
                    style={{ flex: 1, minWidth: 56, padding: '5px 0', fontSize: 11, border: `1px solid ${active ? 'var(--accent)' : 'var(--border)'}`, borderRadius: 6, background: active ? 'var(--accent)' : 'transparent', color: active ? '#fff' : 'var(--ink)', cursor: 'pointer', fontWeight: active ? 600 : 400 }}>
                    {p.l}
                  </button>
                );
              })}
              <div style={{ position: 'relative', flex: 1.2, minWidth: 110 }}>
                <button onClick={() => setShowCustom(v => !v)}
                  style={{ width: '100%', padding: '5px 8px', fontSize: 11, border: `1px solid ${!isPreset || showCustom ? 'var(--accent)' : 'var(--border)'}`, borderRadius: 6, background: !isPreset || showCustom ? 'var(--accent)' : 'transparent', color: !isPreset || showCustom ? '#fff' : 'var(--ink)', cursor: 'pointer', fontWeight: !isPreset ? 600 : 400, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 5 }}>
                  <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M16 2V6M8 2V6M3 10H21"/></svg>
                  {!isPreset ? `${fmtTh(since)} – ${fmtTh(until)}` : 'กำหนดเอง'}
                </button>
                {showCustom && window.DateRangePicker && (
                  <div
                    onClick={(e) => { if (e.target === e.currentTarget) setShowCustom(false); }}
                    style={{
                      position: 'fixed', inset: 0, zIndex: 1000,
                      background: 'rgba(0,0,0,0.45)',
                      display: 'flex', alignItems: 'center', justifyContent: 'center',
                    }}>
                    {React.createElement(window.DateRangePicker, {
                      since,
                      until,
                      inline: true,
                      onChange: (s, e) => { if (s && e) { setSince(s); setUntil(e); } },
                      onClose: () => setShowCustom(false),
                    })}
                  </div>
                )}
              </div>
            </div>
          </div>

          {/* Result — ค้างไว้จนกว่าจะปิด panel เอง */}
          {phase === 'done' && result && (
            <div style={{ padding: 14, background: 'var(--success-subtle, #f0fdf4)', border: '1px solid #bbf7d0', borderRadius: 8, marginBottom: 16 }}>
              <div style={{ fontWeight: 600, color: '#16a34a', fontSize: 14, marginBottom: 4, display: 'flex', alignItems: 'center', gap: 6 }}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#16a34a" strokeWidth="2.5"><path d="M20 6L9 17L4 12"/></svg>
                Sync สำเร็จ
              </div>
              <div style={{ fontSize: 11, color: '#15803d', opacity: 0.8, marginBottom: 8 }}>
                ช่วง {since} → {until}
              </div>
              {Object.entries(result).map(([accId, r]) => (
                <div key={accId} style={{ fontSize: 12, color: '#15803d', lineHeight: 1.7, paddingTop: 8, borderTop: '1px solid #bbf7d0', marginTop: 8 }}>
                  <strong>{AD_ACCOUNTS.find(a => a.id === accId)?.name ?? accId}</strong>
                  {r.error ? (
                    <div style={{ color: '#dc2626', fontSize: 11, marginTop: 2 }}>⚠ {String(r.error).slice(0, 120)}</div>
                  ) : (
                    <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '2px 12px', marginTop: 4, fontFamily: 'var(--mono)' }}>
                      <span>📁 Campaigns: <strong>{r.campaigns ?? 0}</strong></span>
                      <span>📦 Ad Sets: <strong>{r.adsets ?? 0}</strong></span>
                      <span>🎯 Ads: <strong>{r.ads ?? 0}</strong></span>
                      <span>📊 Insights: <strong>{r.insights ?? 0}</strong></span>
                    </div>
                  )}
                </div>
              ))}
              <div style={{ fontSize: 11, color: '#15803d', opacity: 0.7, marginTop: 10 }}>
                กด "ปิด" เพื่อดูผลในแดชบอร์ด หรือ Sync ช่วงอื่นต่อได้เลย
              </div>
            </div>
          )}

          {phase === 'error' && needToken && (
            <div style={{ padding: 12, background: '#fffbeb', border: '1px solid #fcd34d', borderRadius: 8, marginBottom: 16 }}>
              <div style={{ fontWeight: 600, fontSize: 13, color: '#92400e', marginBottom: 6 }}>FB Access Token หมดอายุ / ยังไม่ได้ตั้ง</div>
              <div style={{ fontSize: 12, color: '#78350f', lineHeight: 1.6, marginBottom: 8 }}>
                Token ปัจจุบันใช้ไม่ได้ ต้องไปต่ออายุที่<br/>
                <a href="https://developers.facebook.com/tools/explorer/" target="_blank" rel="noopener" style={{ color: '#92400e', fontWeight: 600 }}>Graph API Explorer</a> แล้วเอา token ใหม่<br/>
                ไป update ที่ Supabase secret <code style={{ background:'#fef3c7', padding:'1px 4px', borderRadius:4 }}>FB_ACCESS_TOKEN</code>
                <br/><br/>
                หรือบอก Claude Code ว่า:
              </div>
              <div style={{ fontFamily: 'var(--mono)', fontSize: 11, background: '#fef3c7', padding: '8px 10px', borderRadius: 6, color: '#78350f', userSelect: 'all' }}>
                sync FB data ตั้งแต่ {since} ถึง {until}
              </div>
            </div>
          )}

          {phase === 'error' && !needToken && errMsg && (
            <div style={{ padding: 12, background: '#fff1f2', border: '1px solid #fecdd3', borderRadius: 8, marginBottom: 16 }}>
              <div style={{ fontWeight: 600, fontSize: 13, color: '#be123c', marginBottom: 4 }}>เกิดข้อผิดพลาด</div>
              <div style={{ fontSize: 11, fontFamily: 'var(--mono)', color: '#9f1239', whiteSpace: 'pre-wrap', wordBreak: 'break-word' }}>
                {typeof errMsg === 'string' ? errMsg : (() => { try { return JSON.stringify(errMsg, null, 2); } catch { return String(errMsg); } })()}
              </div>
            </div>
          )}
        </div>

        {/* Footer */}
        <div style={{ padding: '16px 20px', borderTop: '1px solid var(--border)', display: 'flex', gap: 8 }}>
          <button onClick={onClose} style={{ flex: 1, padding: '8px 0', border: '1px solid var(--border)', borderRadius: 8, background: phase === 'done' ? 'var(--accent)' : 'transparent', color: phase === 'done' ? '#fff' : 'var(--ink)', cursor: 'pointer', fontSize: 13, fontWeight: phase === 'done' ? 600 : 400 }}>
            {phase === 'done' ? 'ปิด' : 'ยกเลิก'}
          </button>
          <button onClick={runSync} disabled={phase === 'running' || !selAccs.length}
            style={{ flex: 2, padding: '8px 0', border: phase === 'done' ? '1px solid var(--border)' : 'none', borderRadius: 8, background: phase === 'done' ? 'transparent' : 'var(--accent)', color: phase === 'done' ? 'var(--ink)' : '#fff', cursor: phase === 'running' ? 'wait' : 'pointer', fontSize: 13, fontWeight: 600, opacity: phase === 'running' || !selAccs.length ? 0.6 : 1 }}>
            {phase === 'running' ? (
              <span style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6 }}>
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" style={{ animation: 'spin 1s linear infinite' }}><path d="M21 12A9 9 0 1112 3"/></svg>
                กำลัง Sync...
              </span>
            ) : phase === 'done' ? '↻ Sync ใหม่' : '↓ Sync ข้อมูล'}
          </button>
        </div>
      </div>
    </div>
  );
};

// ── Auth Gate — checked ก่อน App render ─────────────────────
const AuthGate = ({ children }) => {
  const [user, setUser]       = React.useState(null);
  const [status, setStatus]   = React.useState("loading"); // loading | authed | unauth | forbidden

  React.useEffect(() => {
    // จัดการ /auth/callback ก่อน (set token + redirect — ไม่ render app)
    if (window.Auth.handleCallback()) return;
    const isDev = window.Auth.isDev();
    const token = window.Auth.getToken();
    // production: ไม่มี token → redirect SSO; dev: bypass ด้วย mock user
    if (!token && !isDev) {
      setStatus("unauth");
      window.Auth.loginRedirect();
      return;
    }
    window.Auth.fetchMe()
      .then(u => {
        if (!u) {
          setStatus("unauth");
          if (!isDev) window.Auth.loginRedirect();
          return;
        }
        if (!window.Auth.hasPermission(u, "wandeecf_menu_report")) {
          setUser(u);
          setStatus("forbidden");
          return;
        }
        setUser(u);
        setStatus("authed");
      });
  }, []);

  if (status === "loading" || status === "unauth") {
    return (
      <div style={{ minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column", gap: 12, background: "var(--bg)" }}>
        <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" strokeWidth="2.5" style={{ animation: "spin 0.8s linear infinite" }}>
          <path d="M21 12A9 9 0 1112 3"/>
        </svg>
        <div style={{ color: "var(--ink-faint)", fontSize: 13 }}>
          {status === "loading" ? "กำลังตรวจสอบสิทธิ์…" : "กำลังพา ไปหน้า login…"}
        </div>
      </div>
    );
  }
  if (status === "forbidden") {
    return (
      <div style={{ minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column", gap: 16, padding: 32, textAlign: "center", background: "var(--bg)" }}>
        <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="var(--danger)" strokeWidth="2">
          <circle cx="12" cy="12" r="10"/><path d="M12 8V12M12 16H12.01"/>
        </svg>
        <div style={{ fontSize: 16, fontWeight: 600 }}>ไม่มีสิทธิ์เข้าถึง</div>
        <div style={{ fontSize: 13, color: "var(--ink-faint)" }}>
          คุณ <strong style={{ color: "var(--ink)" }}>{user?.name || user?.username}</strong> ไม่มี permission <code style={{ background: "var(--panel)", padding: "1px 6px", borderRadius: 4 }}>wandeecf_menu_report</code>
        </div>
        <button onClick={() => window.Auth.logout()} style={{ padding: "8px 20px", border: "1px solid var(--border)", borderRadius: 8, background: "var(--bg)", cursor: "pointer", fontSize: 13 }}>
          เปลี่ยน user
        </button>
      </div>
    );
  }
  // authed — render app + pass user via context
  return children(user);
};

window.AuthContext = React.createContext(null);

// ── Main App ─────────────────────────────────────────────────
const App = ({ user }) => {
  const [tweaks, setTweak] = window.useTweaks ? window.useTweaks(wandeeDefaults) : [wandeeDefaults, () => {}];
  const [route, setRoute]                   = React.useState("dashboard");
  const [selectedCampaign, setSelectedCampaign] = React.useState(null);
  const [selectedAd, setSelectedAd]         = React.useState(null);
  const [showBuilder, setShowBuilder]       = React.useState(false);
  const [showCopilot, setShowCopilot]       = React.useState(true);
  const [showSync, setShowSync]             = React.useState(false);
  const [showAccMenu, setShowAccMenu]       = React.useState(false);
  const [activeAccId, setActiveAccId]       = React.useState(null); // null = ทุก account
  const [adAccountUuid, setAdAccountUuid]   = React.useState(null); // UUID ใน Supabase
  const [timeRange, setTimeRange]           = React.useState(() => {
    const r = new URLSearchParams(location.search).get("range");
    return r || "30d";
  });
  const [toast, setToast]                   = React.useState(null);

  // ── Supabase data state ──────────────────────────────────
  const [dbStatus, setDbStatus]   = React.useState("loading");
  const [dataVersion, setDataVersion] = React.useState(0); // increment เพื่อ re-render
  const [tokenStatus, setTokenStatus] = React.useState("unknown"); // unknown | ok | expired
  const [lastSyncAt, setLastSyncAt]   = React.useState(null);
  const [bannerDismissed, setBannerDismissed] = React.useState(false);

  // ── ตรวจ FB Token + freshness ─────────────────────────────
  React.useEffect(() => {
    if (!window.SB) return;
    (async () => {
      try {
        // 1) ดู last_synced_at ล่าสุดของ campaigns
        const { data: last } = await window.SB
          .from('campaigns')
          .select('last_synced_at')
          .order('last_synced_at', { ascending: false })
          .limit(1)
          .maybeSingle();
        if (last?.last_synced_at) setLastSyncAt(last.last_synced_at);

        // 2) Ping fb-sync (narrow date) เพื่อเช็ค token
        const today = new Date().toLocaleDateString('en-CA');
        const res = await fetch(`${SUPABASE_FUNC_URL}/fb-sync`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${SYNC_ANON_KEY}`,
            'x-sync-secret': SYNC_SECRET,
            'x-ping-only': '1',
          },
          body: JSON.stringify({ account_ids: ['729603149949974'], since: today, until: today, ping: true }),
        });
        const data = await res.json().catch(() => null);
        if (!data) { setTokenStatus("unknown"); return; }
        const errMsg = Object.values(data.results || {}).map(r => r?.error || '').join(' ');
        if (/Session has expired|OAuthException|access token|code":190/i.test(errMsg)) {
          setTokenStatus("expired");
        } else {
          setTokenStatus("ok");
        }
      } catch {
        setTokenStatus("unknown");
      }
    })();
  }, []);

  React.useEffect(() => {
    document.documentElement.dataset.theme   = tweaks.theme;
    document.documentElement.style.setProperty("--accent", tweaks.accent);
    document.documentElement.dataset.density = tweaks.density;
  }, [tweaks.theme, tweaks.accent, tweaks.density]);

  // ── Load data from Supabase ──────────────────────────────
  React.useEffect(() => {
    if (!window.DB) { setDbStatus("mock"); return; }

    let realtimeSubs = [];

    const load = async () => {
      try {
        setDbStatus("loading");
        const updates = await window.DB.loadAll();

        if (Object.keys(updates).length > 0) {
          // มีข้อมูลจริง — merge เข้า window.MOCK แล้ว re-render
          Object.assign(window.MOCK, updates);
          setDbStatus("live");
          setDataVersion(v => v + 1);
        } else {
          // DB ว่าง → ใช้ mock data ต่อ
          setDbStatus("mock");
        }

        // ── Realtime: AI Insights ────────────────────────
        const aiSub = window.DB.subscribeToAIInsights(null, (newInsight) => {
          window.MOCK.aiInbox = [
            { ...newInsight, status: "PROPOSED", createdAt: "เมื่อกี้" },
            ...window.MOCK.aiInbox,
          ];
          setDataVersion(v => v + 1);
        });

        // ── Realtime: Orders ─────────────────────────────
        const orderSub = window.DB.subscribeToOrders(null, (event) => {
          if (event.eventType === "INSERT") {
            window.MOCK.orders = [event.new, ...window.MOCK.orders];
          } else if (event.eventType === "UPDATE") {
            window.MOCK.orders = window.MOCK.orders.map(o =>
              o.id === event.new.id ? { ...o, ...event.new } : o
            );
          }
          setDataVersion(v => v + 1);
        });

        realtimeSubs = [aiSub, orderSub];

      } catch (err) {
        console.error("[DB] load failed:", err);
        setDbStatus("error");
      }
    };

    load();

    return () => {
      realtimeSubs.forEach(sub => sub?.unsubscribe?.());
    };
  }, []);

  // ── Reload เมื่อเปลี่ยน timeRange หรือ activeAccount ──────
  React.useEffect(() => {
    if (!window.DB || dbStatus !== "live") return;
    const days = { "1d": 1, "7d": 7, "14d": 14, "30d": 30, "6m": 180, "1y": 365 }[timeRange] ?? 7;
    // แปลง fb_account_id → uuid ก่อน query
    const getUuid = async () => {
      if (!activeAccId) return null;
      const { data } = await window.SB.from('ad_accounts').select('id').eq('fb_account_id', activeAccId).single();
      return data?.id ?? null;
    };
    getUuid().then(uuid => {
      setAdAccountUuid(uuid);
      return window.DB.getCampaigns(uuid, days).then(campaigns => {
        if (campaigns) { window.MOCK.campaigns = campaigns; setDataVersion(v => v + 1); }
      });
    }).catch(console.error);
  }, [timeRange, dbStatus, activeAccId]);

  // ── Nav (re-compute badges จาก MOCK ที่ updated) ─────────
  const nav = React.useMemo(() => [
    { k: "dashboard", l: "Overview",           i: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="3" width="7" height="9"/><rect x="14" y="3" width="7" height="5"/><rect x="14" y="12" width="7" height="9"/><rect x="3" y="16" width="7" height="5"/></svg> },
    { k: "creatives", l: "Creatives",           i: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="9" cy="9" r="2"/><path d="M21 15L16 10L5 21"/></svg> },
    { k: "orders",    l: "Orders × Attribution",i: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3 3H5L5.5 5M7 13H17L21 5H5.5M7 13L5.5 5M7 13L4.7 16.3A1 1 0 005.5 18H17M17 18A2 2 0 1015 20A2 2 0 0017 18ZM9 20A2 2 0 117 18A2 2 0 019 20Z"/></svg>, badge: window.MOCK.orders.length },
    { k: "inbox",     l: "AI Inbox",            i: <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2L13.5 8.5L20 10L13.5 11.5L12 18L10.5 11.5L4 10L10.5 8.5Z"/></svg>, badge: window.MOCK.aiInbox.filter(i => i.status === "PROPOSED").length, accent: true },
    { k: "chat",      l: "AI Chat",             i: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 12C21 16.97 16.97 21 12 21C10.6 21 9.3 20.7 8.1 20.1L3 21L4 16.4C3.4 15.2 3 13.6 3 12C3 7.03 7.03 3 12 3S21 7.03 21 12Z"/></svg> },
    { k: "report",    l: "Client Report",       i: <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M14 2H6A2 2 0 004 4V20A2 2 0 006 22H18A2 2 0 0020 20V8L14 2Z M14 2V8H20 M9 13H15 M9 17H15"/></svg> },
  ], [dataVersion]);  // re-compute badges เมื่อ data update

  const currentEntity = selectedCampaign
    ? { type: "campaign", id: selectedCampaign.id, name: selectedCampaign.name }
    : selectedAd
    ? { type: "ad", id: selectedAd.id, name: selectedAd.name }
    : null;

  const mainStyle = {};
  if (showCopilot && tweaks.aiPosition === "right")  mainStyle.marginRight  = 380;
  if (showCopilot && tweaks.aiPosition === "bottom") mainStyle.marginBottom = 320;

  const showToast = (text, type = "info") => {
    setToast({ text, type });
    setTimeout(() => setToast(null), 3200);
  };

  const handleAiAction = (item, action) => {
    if (action === "apply") {
      // อัปเดต status ใน Supabase ถ้ามี action id
      if (item.suggestedAction?.id && window.SB) {
        window.SB.from("ai_actions")
          .update({ status: "applied", applied_at: new Date().toISOString() })
          .eq("id", item.suggestedAction.id)
          .then(() => {})
          .catch(console.error);
      }
      window.MOCK.aiInbox = window.MOCK.aiInbox.map(i =>
        i.id === item.id ? { ...i, status: "APPLIED" } : i
      );
      setDataVersion(v => v + 1);
      showToast(`✓ ทำตามคำแนะนำแล้ว: ${item.title.substring(0, 40)}...`, "success");
    } else if (action === "dismiss") {
      window.MOCK.aiInbox = window.MOCK.aiInbox.filter(i => i.id !== item.id);
      setDataVersion(v => v + 1);
      showToast("ข้ามคำแนะนำนี้แล้ว");
    } else if (action === "snooze") {
      showToast("เลื่อนไป 24 ชม.");
    }
  };

  const handleCreateCampaign = (draft) => {
    showToast(`✓ สร้างแคมเปญ "${draft.name || "untitled"}" และส่งไปยัง Facebook แล้ว`, "success");
    setShowBuilder(false);
  };

  return (
    <div className="app" data-density={tweaks.density}>
      {/* SIDEBAR */}
      <aside className="sidebar" data-screen-label="Sidebar">
        <div className="brand">
          <div className="brand-mark">
            <svg viewBox="0 0 24 24" width="16" height="16"><path d="M12 2L13.5 8.5L20 10L13.5 11.5L12 18L10.5 11.5L4 10L10.5 8.5Z" fill="currentColor"/></svg>
          </div>
          <div style={{ minWidth: 0 }}>
            <div className="brand-name">Ads · Agent</div>
            <div className="muted small">
              {user ? (
                <span title={user.email || ""}>
                  👤 {user.name || user.username}
                </span>
              ) : "Wandee Agency"}
            </div>
          </div>
          {user && (
            <button onClick={() => window.Auth.logout()}
              title={`ออกจากระบบ (${user.email || user.username})`}
              style={{ marginLeft: "auto", background: "transparent", border: "none", cursor: "pointer", padding: 4, color: "var(--ink-faint)", borderRadius: 4 }}>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <path d="M9 21H5A2 2 0 013 19V5A2 2 0 015 3H9M16 17L21 12L16 7M21 12H9"/>
              </svg>
            </button>
          )}
        </div>

        <div className="org-switcher" style={{ position: 'relative' }} onClick={() => setShowAccMenu(v => !v)}>
          <div className="org-avatar">P</div>
          <div className="org-info">
            <div>Wandee</div>
            <span className="muted small">
              {activeAccId ? AD_ACCOUNTS.find(a => a.id === activeAccId)?.name : 'ทุก Account'}
            </span>
          </div>
          <svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor" style={{ transform: showAccMenu ? 'rotate(180deg)' : 'none', transition: 'transform 0.15s' }}><path d="M7 10L12 15L17 10Z"/></svg>

          {showAccMenu && (
            <div style={{ position: 'absolute', top: '100%', left: 0, right: 0, zIndex: 200, background: 'var(--bg)', border: '1px solid var(--border)', borderRadius: 8, boxShadow: '0 4px 16px rgba(0,0,0,.12)', marginTop: 4, overflow: 'hidden' }}
              onClick={e => e.stopPropagation()}>
              {[{ id: null, name: 'ทุก Account', sub: 'แสดงข้อมูลรวม' }, ...AD_ACCOUNTS].map(acc => (
                <div key={acc.id ?? 'all'} onClick={() => { setActiveAccId(acc.id); setShowAccMenu(false); }}
                  style={{ padding: '9px 14px', cursor: 'pointer', background: activeAccId === acc.id ? 'var(--row-hover)' : 'transparent', fontSize: 13, borderBottom: '1px solid var(--border)' }}>
                  <div style={{ fontWeight: 500 }}>{acc.name}</div>
                  <div style={{ fontSize: 11, color: 'var(--ink-faint)' }}>{acc.sub ?? acc.id}</div>
                </div>
              ))}
            </div>
          )}
        </div>

        <nav className="nav">
          {nav.map(n => (
            <button key={n.k} className={`nav-item ${route === n.k ? "active" : ""} ${n.accent ? "accent" : ""}`}
              onClick={() => { setRoute(n.k); setSelectedCampaign(null); setSelectedAd(null); }}>
              <span className="nav-icon">{n.i}</span>
              <span className="nav-label">{n.l}</span>
              {n.badge != null && n.badge > 0 && <span className={`nav-badge ${n.accent ? "accent" : ""}`}>{n.badge}</span>}
            </button>
          ))}
        </nav>

        <div className="sidebar-foot">
          {/* DB status + Sync trigger */}
          <div style={{ padding: "8px 16px 4px", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
            <DbStatus status={dbStatus} />
            <button onClick={() => setShowSync(true)}
              title={tokenStatus === "expired" ? "FB Token หมดอายุ — กดเพื่อแก้" : "Sync Facebook data"}
              style={{ position: "relative", display: "flex", alignItems: "center", gap: 4, padding: "3px 8px", border: `1px solid ${tokenStatus === "expired" ? "#dc2626" : "var(--border)"}`, borderRadius: 6, background: tokenStatus === "expired" ? "#fef2f2" : "transparent", color: tokenStatus === "expired" ? "#dc2626" : "var(--ink-faint)", cursor: "pointer", fontSize: 11, fontWeight: 500 }}>
              <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5"><path d="M23 4V10H17"/><path d="M1 20V14H7"/><path d="M3.5 9A9 9 0 0120.5 9M20.5 15A9 9 0 013.5 15"/></svg>
              Sync
              {tokenStatus === "expired" && (
                <span style={{ position: "absolute", top: -3, right: -3, width: 8, height: 8, borderRadius: "50%", background: "#dc2626", border: "1.5px solid var(--bg)" }} />
              )}
            </button>
          </div>
          <button className="nav-item">
            <span className="nav-icon"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="12" cy="12" r="3"/><path d="M12 1V5M12 19V23M4.2 4.2L7 7M17 17L19.8 19.8M1 12H5M19 12H23M4.2 19.8L7 17M17 7L19.8 4.2"/></svg></span>
            <span className="nav-label">Settings</span>
          </button>
        </div>
      </aside>

      {/* MAIN */}
      <main className="main" style={mainStyle} data-screen-label={selectedAd ? "AdDetail" : selectedCampaign ? "CampaignDetail" : route}>
        <div className="topbar">
          <div className="topbar-search">
            <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="11" cy="11" r="7"/><path d="M21 21L17 17"/></svg>
            <input placeholder="ค้นหาแคมเปญ ads ออเดอร์... (⌘K)" />
          </div>
          <div className="topbar-actions">
            {!showCopilot && (
              <button className="btn-ghost" onClick={() => setShowCopilot(true)}>
                <svg width="11" height="11" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2L13.5 8.5L20 10L13.5 11.5L12 18L10.5 11.5L4 10L10.5 8.5Z"/></svg>
                AI Co-pilot
              </button>
            )}
            <button className="icon-btn" title="Notifications">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M18 8A6 6 0 006 8C6 15 3 17 3 17H21S18 15 18 8Z M13.7 21A2 2 0 0110.3 21"/></svg>
              <span className="dot"></span>
            </button>
            <div className="user-avatar">น</div>
          </div>
        </div>

        {tokenStatus === "expired" && !bannerDismissed && (
          <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "10px 20px", background: "#fef2f2", borderBottom: "1px solid #fecaca", color: "#991b1b", fontSize: 13 }}>
            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" style={{ flexShrink: 0 }}>
              <path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><path d="M12 9V13M12 17H12.01"/>
            </svg>
            <div style={{ flex: 1 }}>
              <strong>FB Access Token หมดอายุ</strong> — Sync จึงไม่ดึงข้อมูลใหม่
              {lastSyncAt && <span style={{ marginLeft: 8, opacity: 0.75, fontSize: 12 }}>(ข้อมูลล่าสุด: {new Date(lastSyncAt).toLocaleDateString('th-TH')})</span>}
            </div>
            <button onClick={() => setShowSync(true)} style={{ padding: "5px 12px", background: "#dc2626", color: "#fff", border: "none", borderRadius: 6, fontSize: 12, fontWeight: 600, cursor: "pointer" }}>
              แก้ไข Token
            </button>
            <button onClick={() => setBannerDismissed(true)} title="ปิด" style={{ padding: 4, background: "transparent", border: "none", color: "#991b1b", cursor: "pointer", display: "flex" }}>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M18 6L6 18M6 6L18 18"/></svg>
            </button>
          </div>
        )}

        <div className="content">
          {selectedAd ? (
            <AdDetail ad={selectedAd} onBack={() => setSelectedAd(null)} />
          ) : route === "dashboard" ? (
            <Dashboard
              timeRange={timeRange}
              setTimeRange={setTimeRange}
              adAccountId={adAccountUuid}
              onSelectCampaign={(c) => setSelectedCampaign(c)}
              onSelectAd={(a) => setSelectedAd(a)}
              onOpenBuilder={() => setShowBuilder(true)}
            />
          ) : route === "inbox" ? (
            <AIInbox onAction={handleAiAction} />
          ) : route === "chat" ? (
            <AIChat />
          ) : route === "orders" ? (
            <OrdersAttribution />
          ) : route === "creatives" ? (
            <CreativeLibrary />
          ) : route === "report" ? (
            <ClientReport />
          ) : null}
        </div>
      </main>

      {/* AI COPILOT */}
      {showCopilot && (
        <CopilotPanel
          position={tweaks.aiPosition}
          currentScreen={route}
          currentEntity={currentEntity}
          onAction={handleAiAction}
          onClose={() => setShowCopilot(false)}
        />
      )}

      {/* BUILDER */}
      {showBuilder && (
        <CampaignBuilder onClose={() => setShowBuilder(false)} onCreate={handleCreateCampaign} />
      )}

      {/* SYNC PANEL */}
      {showSync && (
        <SyncPanel
          activeAccId={activeAccId}
          onClose={() => setShowSync(false)}
          onSyncDone={() => {
            // ⭐ ไม่ปิด panel — ให้ผลลัพธ์ค้างไว้จนกว่า user ปิดเอง
            // refresh data เบื้องหลัง
            if (window.DB) window.DB.loadAll().then(updates => {
              if (Object.keys(updates).length) { Object.assign(window.MOCK, updates); setDataVersion(v => v + 1); }
            });
          }}
        />
      )}

      {/* TOAST */}
      {toast && (
        <div className={`toast ${toast.type}`}>{toast.text}</div>
      )}

      {/* TWEAKS */}
      {window.TweaksPanel && (
        <window.TweaksPanel title="Tweaks">
          <window.TweakSection title="Theme">
            <window.TweakRadio label="Mode" value={tweaks.theme} onChange={(v) => setTweak("theme", v)} options={[
              { label: "Light", value: "light" },
              { label: "Dark", value: "dark" },
            ]} />
            <window.TweakColor label="Accent" value={tweaks.accent} options={["#3b6ef5", "#0f766e", "#7c3aed", "#e11d48"]} onChange={(v) => setTweak("accent", v)} />
          </window.TweakSection>
          <window.TweakSection title="Layout">
            <window.TweakRadio label="Density" value={tweaks.density} onChange={(v) => setTweak("density", v)} options={[
              { label: "Compact", value: "compact" },
              { label: "Comfort", value: "comfortable" },
            ]} />
          </window.TweakSection>
          <window.TweakSection title="AI Co-pilot">
            <window.TweakSelect label="ตำแหน่ง" value={tweaks.aiPosition} onChange={(v) => setTweak("aiPosition", v)} options={[
              { label: "Right docked", value: "right" },
              { label: "Bottom bar", value: "bottom" },
              { label: "Floating", value: "floating" },
            ]} />
            <window.TweakToggle label="Show AI hints" value={tweaks.showAiHints} onChange={(v) => setTweak("showAiHints", v)} />
          </window.TweakSection>
        </window.TweaksPanel>
      )}
    </div>
  );
};

ReactDOM.createRoot(document.getElementById("root")).render(
  <AuthGate>
    {(user) => (
      <window.AuthContext.Provider value={user}>
        <App user={user} />
      </window.AuthContext.Provider>
    )}
  </AuthGate>
);
