/* ========================================================================
   screens-facebook.jsx — Facebook Page scheduler + calendar
   ====================================================================== */

let FacebookCalendarScreen = () => (
  <div style={{ height: "100%", display: "flex", background: "#1A1813" }}>
    <SidebarNav active="fb-calendar" />
    <div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }}>
      <TopBar />
      <div style={{ flex: 1, overflowY: "auto", padding: "24px 28px 40px" }}>
        <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 10.5, letterSpacing: "0.22em", color: "#EFFF00", fontWeight: 800, textTransform: "uppercase" }}>FACEBOOK CALENDAR</div>
        <h1 style={{ fontFamily: "'Anton', Impact, sans-serif", fontSize: 48, lineHeight: 1, textTransform: "uppercase", margin: "6px 0 0", color: "#FFF" }}>Loading…</h1>
      </div>
    </div>
  </div>
);

/* ── Facebook news-feed post card ──────────────────────────────────────── */
const FbPostCard = ({ post, onPublish, publishingId, fbAccount }) => {
  const [expanded, setExpanded] = React.useState(false);
  const img = post.imageUrl || post.publicUrl;
  const isPostedSt = ["Posted", "posted", "published", "sent"].includes(String(post.status || "").toLowerCase());
  const hashStr = Array.isArray(post.hashtags)
    ? post.hashtags.map(h => h.startsWith("#") ? h : `#${h}`).join(" ")
    : (post.hashtags || "");
  const captionFull = [post.hook, post.caption, hashStr].filter(Boolean).join("\n\n");
  const captionShort = captionFull.length > 180 ? captionFull.slice(0, 180) + "…" : captionFull;
  const schedAt = post.date ? new Date(`${post.date}T${post.time || "09:00"}:00Z`) : null;
  const timeLabel = isPostedSt && post.postedAt
    ? (() => {
        const d = new Date(post.postedAt);
        const diff = Math.max(0, Math.floor((Date.now() - d) / 60000));
        if (diff < 60) return `${diff}m ago`;
        if (diff < 1440) return `${Math.floor(diff/60)}h ago`;
        return d.toLocaleDateString("en-GB", { day: "numeric", month: "short" });
      })()
    : schedAt
    ? schedAt.toLocaleDateString("en-GB", { day: "numeric", month: "short" }) + " · " + (post.time || "09:00")
    : "Draft";

  return (
    <div style={{ background: "#242526", border: "1px solid #3A3B3C", borderRadius: 10, overflow: "hidden", display: "flex", flexDirection: "column" }}>
      {/* FB post header */}
      <div style={{ padding: "14px 16px 0", display: "flex", alignItems: "flex-start", gap: 10 }}>
        <div style={{ width: 40, height: 40, borderRadius: "50%", background: "#B8FF1A", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
          <span style={{ fontFamily: "Anton, Impact, sans-serif", fontWeight: 700, fontSize: 21, color: "#07080A", lineHeight: 1 }}>S</span>
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontWeight: 700, fontSize: 14, color: "#E4E6EB", lineHeight: 1.2 }}>SHIFT Performance</div>
          <div style={{ fontSize: 12, color: "#B0B3B8", display: "flex", alignItems: "center", gap: 4, marginTop: 2 }}>
            <span>{timeLabel}</span>
            <span style={{ fontSize: 8 }}>·</span>
            <Icon name="globe" size={11} stroke={2} color="#B0B3B8" />
          </div>
        </div>
        <div style={{ color: "#B0B3B8", fontSize: 20, lineHeight: 1, cursor: "default", padding: "0 2px", letterSpacing: 1 }}>···</div>
      </div>

      {/* Caption */}
      {captionFull && (
        <div style={{ padding: "10px 16px 0", fontSize: 14, color: "#E4E6EB", lineHeight: 1.6, whiteSpace: "pre-line" }}>
          {expanded ? captionFull : captionShort}
          {captionFull.length > 180 && (
            <span
              onClick={() => setExpanded(v => !v)}
              style={{ color: "#B0B3B8", cursor: "pointer", marginLeft: 4, fontSize: 13 }}
            >
              {expanded ? " See less" : " See more"}
            </span>
          )}
        </div>
      )}

      {/* Image */}
      {img && (
        <div style={{ marginTop: 12, background: "#18191A", aspectRatio: "1.91/1", overflow: "hidden", flexShrink: 0 }}>
          <img src={img} alt="" style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }} />
        </div>
      )}

      {/* Status badge */}
      <div style={{ padding: "10px 16px 0", display: "flex", alignItems: "center", gap: 6 }}>
        <span style={{ width: 6, height: 6, borderRadius: "50%", background: isPostedSt ? "#4ADE80" : schedAt ? "#EFFF00" : "#5C5C5C", display: "inline-block", flexShrink: 0 }} />
        <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 9, letterSpacing: "0.12em", fontWeight: 700, color: isPostedSt ? "#4ADE80" : schedAt ? "#EFFF00" : "#5C5C5C" }}>
          {isPostedSt ? "POSTED" : schedAt ? `SCHEDULED · ${timeLabel}` : "DRAFT"}
        </span>
        {post.type && <span style={{ marginLeft: "auto", fontFamily: "'JetBrains Mono', monospace", fontSize: 8, color: "#5C5C5C", letterSpacing: "0.1em" }}>{String(post.type).toUpperCase()}</span>}
      </div>

      {/* Engagement (decorative) */}
      <div style={{ padding: "8px 16px 0", display: "flex", alignItems: "center", justifyContent: "space-between", borderBottom: "1px solid #3A3B3C", paddingBottom: 8 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 4, fontSize: 13, color: "#B0B3B8" }}>
          <span>👍</span><span>❤️</span><span>🔥</span>
          <span style={{ marginLeft: 3 }}>—</span>
        </div>
        <span style={{ fontSize: 12, color: "#B0B3B8" }}>— comments</span>
      </div>

      {/* Action bar */}
      <div style={{ display: "flex", gap: 0, padding: "4px 8px 8px" }}>
        {[["👍", "Like"], ["💬", "Comment"], ["↗", "Share"]].map(([ico, label]) => (
          <div key={label} style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: 5, padding: "7px 0", borderRadius: 6, cursor: "default", fontSize: 13, color: "#B0B3B8", fontWeight: 600 }}>
            <span>{ico}</span><span>{label}</span>
          </div>
        ))}
      </div>

      {/* Publish now button (unposted only) */}
      {!isPostedSt && (
        <div style={{ padding: "0 12px 12px" }}>
          <button
            className="btn btn-secondary btn-sm"
            style={{ width: "100%", justifyContent: "center", borderColor: fbAccount ? "#4ADE80" : "#3A372F", color: fbAccount ? "#4ADE80" : "#5C5C5C" }}
            onClick={() => onPublish(post)}
            disabled={!fbAccount || publishingId === post.id}
          >
            {publishingId === post.id
              ? <><span className="bolt-thinking" style={{ display: "inline-block", lineHeight: 0 }}><BoltMini size={11} color="#EFFF00" /></span> Publishing…</>
              : <><Icon name="facebook" size={11} stroke={2} /> Publish now</>}
          </button>
        </div>
      )}
    </div>
  );
};

FacebookCalendarScreen = () => {
  const initialScheduledQueue = (() => {
    try { return JSON.parse(localStorage.getItem("boltkit.fbPosts.v1") || "[]"); } catch { return []; }
  })();
  const [queuePosts, setQueuePosts] = React.useState(Array.isArray(initialScheduledQueue) ? initialScheduledQueue : []);
  const firstScheduled = queuePosts.find(post => post.date)?.date || new Date().toISOString().slice(0, 10);
  const [visibleMonth, setVisibleMonth] = React.useState(() => {
    const start = new Date(`${firstScheduled}T12:00:00`);
    return new Date(start.getFullYear(), start.getMonth(), 1, 12);
  });
  const [selectedDate, setSelectedDate] = React.useState(firstScheduled);
  const [selectedPost, setSelectedPost] = React.useState(queuePosts[0]?.id || "fb-post-01");
  const [time, setTime] = React.useState(queuePosts[0]?.time || "09:00");
  const [platforms, setPlatforms] = React.useState(["Facebook"]);
  const [calendarMode, setCalendarMode] = React.useState("Month");
  const [publishingId, setPublishingId] = React.useState(null);
  const [fbAccount, setFbAccount] = React.useState(null);
  const [autoDateStatus, setAutoDateStatus] = React.useState("");
  const [autopilotState, setAutopilotState] = React.useState("idle"); // idle | pushing | on | error
  const [feedMode, setFeedMode] = React.useState("All"); // All | Upcoming | Posted
  const [fbDragPostId,   setFbDragPostId]   = React.useState(null);
  const [fbDragOverDate, setFbDragOverDate] = React.useState(null);
  const [confirmClear,   setConfirmClear]   = React.useState(false);

  // Auto-jump ref: navigates visibleMonth to first scheduled post ONCE when posts first load
  const hasAutoJumpedFB = React.useRef(false);
  React.useEffect(() => {
    if (hasAutoJumpedFB.current || !queuePosts.length) return;
    const first = queuePosts.find(p => p.date && String(p.date).match(/\d{4}-\d{2}-\d{2}/));
    if (!first) return;
    const d = new Date(`${first.date}T12:00:00`);
    setVisibleMonth(new Date(d.getFullYear(), d.getMonth(), 1, 12));
    setSelectedDate(first.date);
    hasAutoJumpedFB.current = true;
  }, [queuePosts.length]);

  React.useEffect(() => {
    fetch("/api/meta/status").then(r => r.json()).then(d => {
      if (d.accounts?.[0]) setFbAccount(d.accounts[0]);
    }).catch(() => {});
  }, []);

  // Reload queue whenever generate screen (or any screen) writes new posts
  React.useEffect(() => {
    const reload = () => {
      try {
        const posts = JSON.parse(localStorage.getItem("boltkit.fbPosts.v1") || "[]");
        setQueuePosts(Array.isArray(posts) ? posts : []);
      } catch {}
    };
    window.addEventListener("boltkit:saved", reload);
    const t = setInterval(reload, 10000);
    return () => { clearInterval(t); window.removeEventListener("boltkit:saved", reload); };
  }, []);

  // Ref to trigger an immediate server reload from outside this effect (e.g. on project switch)
  const fbLoadTrigger = React.useRef(null);

  // Load from Supabase on mount — syncs status changes; never removes local posts
  React.useEffect(() => {
    let running = false;
    const loadFromServer = async () => {
      if (running) return; // prevent overlapping fetches
      running = true;
      try {
        const proj = (() => { try { return JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch { return {}; } })();
        const ctrl = new AbortController();
        const timer = setTimeout(() => ctrl.abort(), 20000);
        let resp;
        try {
          resp = await fetch("/api/supabase-facebook-posts", {
            method: "POST", headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ action: "load", project: proj }),
            signal: ctrl.signal,
          });
        } finally { clearTimeout(timer); }
        const data = await resp.json();
        if (!data.ok || !Array.isArray(data.posts)) return;
        const local = (() => { try { return JSON.parse(localStorage.getItem("boltkit.fbPosts.v1") || "[]"); } catch { return []; } })();
        if (!data.posts.length) return; // server empty — keep whatever local has
        if (!local.length) {
          // Don't restore from server if the user explicitly cleared within the last 30 min
          try {
            const clrAt = parseInt(localStorage.getItem("boltkit.fbCalClearedAt") || "0");
            if (clrAt && (Date.now() - clrAt) < 60 * 60 * 1000) return;
          } catch {}
          // First load with empty local: populate from server
          try { localStorage.setItem("boltkit.fbPosts.v1", JSON.stringify(data.posts)); } catch {}
          setQueuePosts(data.posts);
          return;
        }
        // Status-sync mode: update statuses from server; keep all local posts intact
        const serverMap = new Map(data.posts.map(p => [p.id, p]));
        const localIds = new Set(local.map(p => p.id));
        let changed = false;
        const synced = local.map(p => {
          const sv = serverMap.get(p.id);
          if (!sv) return p;
          if (sv.status !== p.status) { changed = true; return { ...p, status: sv.status }; }
          return p;
        });
        // Add posts from server that local doesn't know about (cross-device sync)
        const serverOnly = data.posts.filter(p => !localIds.has(p.id));
        if (serverOnly.length) { changed = true; synced.push(...serverOnly); }
        if (changed) {
          try { localStorage.setItem("boltkit.fbPosts.v1", JSON.stringify(synced)); } catch {}
          setQueuePosts(synced);
        }
      } catch {} finally { running = false; }
    };
    fbLoadTrigger.current = loadFromServer;
    loadFromServer();
    const t = setInterval(loadFromServer, 120000); // refresh from server every 2 min
    return () => { clearInterval(t); fbLoadTrigger.current = null; };
  }, []);

  // When user switches project — clear this project's local cache and reload from Supabase
  React.useEffect(() => {
    const onSwitch = () => {
      try { localStorage.setItem("boltkit.fbPosts.v1", JSON.stringify([])); } catch {}
      setQueuePosts([]);
      setDraftQueue([]);
      setTimeout(() => fbLoadTrigger.current?.(), 150);
    };
    window.addEventListener("boltkit:project-switched", onSwitch);
    return () => window.removeEventListener("boltkit:project-switched", onSwitch);
  }, []);

  // Count of unscheduled drafts in the generate-screen store
  const [draftQueue, setDraftQueue] = React.useState(() => {
    try { return JSON.parse(localStorage.getItem("boltkit.fbDraftPosts.v1") || "[]"); } catch { return []; }
  });
  React.useEffect(() => {
    const reload = () => {
      try { setDraftQueue(JSON.parse(localStorage.getItem("boltkit.fbDraftPosts.v1") || "[]")); } catch {}
    };
    window.addEventListener("boltkit:saved", reload);
    const t = setInterval(reload, 8000);
    return () => { clearInterval(t); window.removeEventListener("boltkit:saved", reload); };
  }, []);

  const [scheduling, setScheduling] = React.useState(false);
  const [importPerDay, setImportPerDay] = React.useState(4); // posts/day for the import (1-12)

  // Calendar block popup (click on an event chip → edit/delete/move)
  const [calPopup, setCalPopup] = React.useState(null); // { post, x, y }
  const openCalPopup = (e, post) => {
    e.stopPropagation();
    const rect = e.currentTarget.getBoundingClientRect();
    const x = Math.min(rect.left, window.innerWidth - 310);
    const y = Math.min(rect.bottom + 6, window.innerHeight - 340);
    setCalPopup({ post: { ...post }, origId: post.id, x, y });
  };
  const updateCalPopupField = (field, value) => {
    setCalPopup(prev => prev ? { ...prev, post: { ...prev.post, [field]: value } } : prev);
  };
  const saveCalPopup = () => {
    if (!calPopup) return;
    const next = queuePosts.map(p => p.id === calPopup.origId ? { ...p, ...calPopup.post } : p);
    saveCalendarQueue(next);
    // Jump calendar to new date if moved
    if (calPopup.post.date && calPopup.post.date !== calPopup.post.date) {
      const d = new Date(`${calPopup.post.date}T12:00:00`);
      setVisibleMonth(new Date(d.getFullYear(), d.getMonth(), 1, 12));
      setSelectedDate(calPopup.post.date);
    }
    setCalPopup(null);
    window.BoltKitToast?.({ msg: "Post updated.", type: "success" });
  };
  const deleteCalPopup = () => {
    if (!calPopup) return;
    const next = queuePosts.filter(p => p.id !== calPopup.origId);
    saveCalendarQueue(next);
    setCalPopup(null);
    window.BoltKitToast?.({ msg: "Post removed from calendar.", type: "success" });
  };

  // Import all generate-screen drafts into the calendar with auto-assigned dates
  const importDraftsToCalendar = async () => {
    let drafts = [];
    try { drafts = JSON.parse(localStorage.getItem("boltkit.fbDraftPosts.v1") || "[]"); } catch {}
    if (!Array.isArray(drafts) || !drafts.length) {
      window.BoltKitToast?.({ msg: "No Facebook posts in the generate queue.", type: "error" });
      return;
    }
    setScheduling(true);
    try {
      const ppd = Math.max(1, Math.min(12, importPerDay));
      // Distribute times evenly between 08:00 and 20:00
      const genTimes = (n) => {
        if (n <= 1) return ["09:00"];
        const START = 8 * 60, END = 20 * 60;
        return Array.from({ length: n }, (_, i) => {
          const mins = Math.round(START + (END - START) * i / (n - 1));
          return `${String(Math.floor(mins / 60)).padStart(2,"0")}:${String(mins % 60).padStart(2,"0")}`;
        });
      };
      const TIMES = genTimes(ppd);
      const tomorrow = new Date();
      tomorrow.setDate(tomorrow.getDate() + 1);
      tomorrow.setHours(0, 0, 0, 0);
      const dKey = (d) => `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,"0")}-${String(d.getDate()).padStart(2,"0")}`;
      const toSchedule = drafts.map((post, i) => {
        const d = new Date(tomorrow);
        d.setDate(d.getDate() + Math.floor(i / ppd));
        return { ...post, date: dKey(d), time: TIMES[i % ppd], status: "Scheduled", platforms: ["Facebook"] };
      });
      let existing = [];
      try { existing = JSON.parse(localStorage.getItem("boltkit.fbPosts.v1") || "[]"); } catch {}
      if (!Array.isArray(existing)) existing = [];
      const ids = new Set(toSchedule.map(p => p.id));
      const merged = [...toSchedule, ...existing.filter(p => !ids.has(p.id))];

      // Save to localStorage FIRST so the boltkit:saved reload sees the new data
      try { localStorage.setItem("boltkit.fbPosts.v1", JSON.stringify(merged)); } catch (e) {
        console.warn("[importDraftsToCalendar] localStorage save failed:", e.message);
      }
      // Now update React state and notify other components
      setQueuePosts(merged);
      window.dispatchEvent(new Event("boltkit:saved"));

      // Jump calendar to first imported date
      const first = new Date(`${toSchedule[0].date}T12:00:00`);
      setVisibleMonth(new Date(first.getFullYear(), first.getMonth(), 1, 12));
      setSelectedDate(toSchedule[0].date);

      const days = Math.ceil(drafts.length / ppd);
      window.BoltKitToast?.({ msg: `${toSchedule.length} posts imported · ${ppd}/day across ${days} days.`, type: "success" });

      // Push to server in background (non-blocking)
      try {
        let proj = {};
        try { proj = JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch {}
        await fetch("/api/supabase-facebook-posts", {
          method: "POST", headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ action: "save", project: proj, posts: merged }),
        });
      } catch (e) { console.warn("[importDraftsToCalendar] server sync failed:", e.message); }
    } catch (e) {
      console.error("[importDraftsToCalendar] failed:", e.message);
      window.BoltKitToast?.({ msg: `Import failed: ${e.message}`, type: "error" });
    } finally {
      setScheduling(false);
    }
  };

  const postMissedNow = async () => {
    const now = new Date();
    const missed = queuePosts.filter(p => {
      const at = p.date ? new Date(`${p.date}T${p.time || "09:00"}:00Z`) : null;
      const st = String(p.status || "").toLowerCase();
      return at && at <= now && !["posted", "published", "sent"].includes(st);
    });
    if (!missed.length) return;
    const base = new Date();
    const rescheduled = missed.map((p, i) => {
      const slot = new Date(base.getTime() + (i + 1) * 10 * 60 * 1000);
      const d = slot.toISOString().slice(0, 10);
      const hh = String(slot.getHours()).padStart(2, "0");
      const mm = String(slot.getMinutes()).padStart(2, "0");
      return { ...p, date: d, time: `${hh}:${mm}`, status: "Scheduled" };
    });
    const ids = new Set(rescheduled.map(p => p.id));
    const next = queuePosts.map(p => ids.has(p.id) ? rescheduled.find(r => r.id === p.id) : p);
    saveCalendarQueue(next);
    window.BoltKitToast?.({ msg: `${missed.length} missed post${missed.length !== 1 ? "s" : ""} rescheduled in 10-min intervals.`, type: "success" });
    try {
      let projectData = {};
      try { projectData = JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch {}
      await fetch("/api/supabase-facebook-posts", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action: "save", project: projectData, posts: next }),
      });
    } catch {}
  };

  // Nuclear clear — delete EVERYTHING
  const clearFbSchedule = () => {
    const kept = [];
    try { localStorage.setItem("boltkit.fbCalClearedAt", String(Date.now())); } catch {}
    try { localStorage.setItem("boltkit.fbPosts.v1", JSON.stringify(kept)); } catch {}
    setQueuePosts(kept);
    setAutopilotState("idle");
    setConfirmClear(false);
    window.BoltKitToast?.({ msg: "Clearing… please wait.", type: "success" });
    const project = (() => { try { return JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch { return {}; } })();
    const supaDelete = typeof apiJson === "function"
      ? apiJson("/api/supabase-facebook-posts", { action: "save", project, posts: kept })
          .then(() => "ok")
          .catch(err => { window.BoltKitToast?.({ msg: "DB clear failed — will reload anyway.", type: "error" }); return "error"; })
      : Promise.resolve("skip");
    Promise.race([supaDelete, new Promise(r => setTimeout(() => r("timeout"), 10000))]).then(result => {
      window.BoltKitToast?.({ msg: result === "ok" ? "Cleared — reloading." : "Reloading (DB may still clear).", type: "success" });
      setTimeout(() => window.location.reload(), 600);
    });
  };

  // Auto-date all undated posts starting tomorrow, 4× per day
  const autoDateAllPosts = () => {
    const undated = queuePosts.filter(p => !p.date || !String(p.date).match(/\d{4}-\d{2}-\d{2}/));
    if (!undated.length) { window.BoltKitToast?.({ msg: "All posts already have dates.", type: "success" }); return; }
    const TIMES = ["08:00", "12:00", "17:00", "20:00"];
    const tomorrow = new Date();
    tomorrow.setDate(tomorrow.getDate() + 1);
    tomorrow.setHours(0, 0, 0, 0);
    const dKey = (d) => `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,"0")}-${String(d.getDate()).padStart(2,"0")}`;
    const dated = undated.map((post, i) => {
      const d = new Date(tomorrow);
      d.setDate(d.getDate() + Math.floor(i / 4));
      return { ...post, date: dKey(d), time: TIMES[i % 4], status: "Scheduled" };
    });
    const ids = new Set(dated.map(p => p.id));
    const next = [...dated, ...queuePosts.filter(p => !ids.has(p.id))];
    saveCalendarQueue(next);
    // Jump calendar to first new date
    const first = new Date(`${dated[0].date}T12:00:00`);
    setVisibleMonth(new Date(first.getFullYear(), first.getMonth(), 1, 12));
    setSelectedDate(dated[0].date);
    const days = Math.ceil(undated.length / 4);
    setAutoDateStatus(`${undated.length} posts auto-dated across ${days} days starting ${dated[0].date}.`);
    window.BoltKitToast?.({ msg: `${undated.length} posts scheduled across ${days} days.`, type: "success" });
  };

  // Push all posts to Supabase so the server cron can fire them even with the laptop closed
  const startServerAutopilot = async () => {
    const scheduled = queuePosts.filter(p => p.date && String(p.date).match(/\d{4}-\d{2}-\d{2}/));
    if (!scheduled.length) {
      window.BoltKitToast?.({ msg: "No dated posts to push. Use Auto-date first.", type: "error" }); return;
    }
    setAutopilotState("pushing");
    window.BoltKitToast?.({ msg: `Pushing ${scheduled.length} posts to server…`, type: "loading" });
    const ctrl = new AbortController();
    const autopilotTimer = setTimeout(() => ctrl.abort(), 30000);
    try {
      let projectData = {};
      try { projectData = JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch {}
      const resp = await fetch("/api/supabase-facebook-posts", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action: "save", project: projectData, posts: queuePosts }),
        signal: ctrl.signal,
      });
      const data = await resp.json();
      if (data.ok) {
        setAutopilotState("on");
        window.BoltKitToast?.({ msg: `${data.count || scheduled.length} posts saved to server. Autopilot running every 15 min — close your laptop.`, type: "success" });
      } else {
        throw new Error(data.error || "Save failed");
      }
    } catch (err) {
      setAutopilotState("error");
      window.BoltKitToast?.({ msg: "Server push failed: " + (err.name === "AbortError" ? "Timed out after 30s" : err.message), type: "error" });
    } finally {
      clearTimeout(autopilotTimer);
    }
  };

  const publishNow = async (post) => {
    const raw = queuePosts.find(p => p.id === post.id) || post;
    const mediaUrl = raw.publicUrl || raw.imageUrl || raw.remoteUrl || post.publicUrl || post.imageUrl;
    if (!mediaUrl) {
      window.BoltKitToast?.({ msg: "No image URL — upload the image to Supabase first.", type: "error" }); return;
    }
    if (mediaUrl.startsWith("blob:") || mediaUrl.startsWith("data:")) {
      window.BoltKitToast?.({ msg: "Image is still uploading to Supabase. Wait a moment then try again.", type: "error" }); return;
    }
    setPublishingId(post.id);
    window.BoltKitToast?.({ msg: "Sending to Facebook…", type: "loading" });
    try {
      const rawHashtags = raw.hashtags || post.hashtags || [];
      const hashtagStr = Array.isArray(rawHashtags) ? rawHashtags.map(h => h.startsWith("#") ? h : `#${h}`).join(" ") : String(rawHashtags);
      const captionText = [raw.hook || post.hook, raw.caption || post.caption, hashtagStr].filter(Boolean).join("\n\n");
      const resp = await fetch("/api/facebook-publish-now", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ mediaUrl, caption: captionText, mediaType: "IMAGE" }),
      });
      const data = await resp.json();
      if (data.ok && !data.skipped) {
        saveCalendarQueue(queuePosts.map(p => p.id === post.id ? { ...p, status: "Posted", postedAt: new Date().toISOString() } : p));
        window.BoltKitToast?.({ msg: "Posted to Facebook!", type: "success" });
      } else if (data.skipped) {
        window.BoltKitToast?.({ msg: "Publishing is disabled — set ENABLE_FACEBOOK_PUBLISHING=true in Vercel.", type: "error" });
      } else {
        window.BoltKitToast?.({ msg: data.error || "Publish failed.", type: "error" });
      }
    } catch (err) {
      window.BoltKitToast?.({ msg: "Publish failed: " + err.message, type: "error" });
    }
    setPublishingId(null);
  };

  const saveCalendarQueue = (next) => {
    // If adding posts back, clear the "recently cleared" flag so Supabase sync resumes normally
    if (next.length > 0) { try { localStorage.removeItem("boltkit.fbCalClearedAt"); } catch {} }
    try { localStorage.setItem("boltkit.fbPosts.v1", JSON.stringify(next)); } catch {}
    setQueuePosts(next);
    window.dispatchEvent(new Event("boltkit:saved"));
    // Push to Supabase in background so posts survive page refreshes
    const proj = (() => { try { return JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch { return {}; } })();
    fetch("/api/supabase-facebook-posts", {
      method: "POST", headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ action: "save", project: proj, posts: next }),
    }).catch(() => {});
  };

  const monthStart = new Date(visibleMonth.getFullYear(), visibleMonth.getMonth(), 1, 12);
  const monthLabel = monthStart.toLocaleDateString("en-GB", { month: "long", year: "numeric" });
  const daysInMonth = new Date(visibleMonth.getFullYear(), visibleMonth.getMonth() + 1, 0).getDate();
  const gridOffset = (monthStart.getDay() + 6) % 7;

  const posts = queuePosts.length ? queuePosts.map((post, index) => ({
    id: post.id || `fb-scheduled-${index}`,
    label: post.title || post.mediaName || post.caption || `Facebook post ${index + 1}`,
    type: post.type || "Post",
    ready: String(post.status || "").toLowerCase() === "scheduled",
    date: post.date || "",
    time: post.time || "09:00",
    caption: post.caption || "",
    platforms: post.platforms || ["Facebook"],
    storyLink: post.storyLink || "",
    scheduleStarted: post.scheduleStarted,
    imageUrl: post.publicUrl || post.imageUrl || post.remoteUrl || post.previewUrl || "",
    publicUrl: post.publicUrl || post.imageUrl || post.remoteUrl || "",
  })) : [];

  const platformsAll = [
    { name: "Facebook", icon: "facebook", connected: false, note: "Page post + Story" },
    { name: "Instagram", icon: "insta", connected: false, note: "Feed, Reels, Stories" },
    { name: "TikTok", icon: "tiktok", connected: false, note: "Short vertical video" },
    { name: "YouTube", icon: "youtube", connected: false, note: "Shorts" },
    { name: "LinkedIn", icon: "linkedin", connected: false, note: "Founder post" },
  ];

  const now = new Date();
  const scheduledAt = (post = {}) => post.date ? new Date(`${post.date}T${post.time || "09:00"}:00Z`) : null;
  const isPastScheduled = (post = {}) => {
    const date = scheduledAt(post);
    const status = String(post.status || "").toLowerCase();
    return Boolean(date && date <= now && !["posted", "published", "sent"].includes(status));
  };
  const platformClass = (platform = "") => `platform-${String(platform).toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
  const postStage = (post = {}) => {
    if (isPastScheduled(post)) return "Missed time";
    if (post.scheduleStarted) return "Confirmed";
    if (post.date) return post.ready ? "Ready to post" : "Scheduled";
    return post.ready ? "Ready" : "Draft";
  };
  const postStageClass = (post = {}) => `stage-${postStage(post).toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;

  const eventsByDate = posts.reduce((map, post, index) => {
    if (!post.date || !String(post.date).match(/\d{4}-\d{2}-\d{2}/)) return map;
    const key = post.date;
    const platformList = post.platforms?.length ? post.platforms : ["Facebook"];
    map[key] = [...(map[key] || []), ...platformList.map(platform => ({ label: `${platform.slice(0, 2).toUpperCase()} ${index + 1}`, platform, post, status: postStage(post) }))];
    return map;
  }, {});

  const selected = posts.find(post => post.id === selectedPost) || posts[0];

  React.useEffect(() => {
    if (!posts.length) return;
    if (!posts.some(post => post.id === selectedPost)) setSelectedPost(posts[0].id);
  }, [posts.length, selectedPost]);

  React.useEffect(() => {
    if (!selected) return;
    setTime(selected.time || "09:00");
    setPlatforms(selected.platforms?.length ? selected.platforms : ["Facebook"]);
  }, [selected?.id]);

  const togglePlatform = (name) => {
    setPlatforms((current) => current.includes(name) ? current.filter(item => item !== name) : [...current, name]);
  };

  const scheduleSelectedPost = () => {
    if (!queuePosts.length || !selected?.id) {
      window.BoltKitToast?.("Import posts first, then schedule them here.");
      return;
    }
    const selectedTime = /^\d{2}:\d{2}$/.test(String(time || "")) ? time : "09:00";
    const scheduledAt = new Date(`${selectedDate}T${selectedTime}:00`);
    if (scheduledAt <= new Date()) {
      window.BoltKitToast?.("Choose a future date and time.");
      return;
    }
    const next = queuePosts.map((post, index) => {
      const postId = post.id || `fb-scheduled-${index}`;
      if (postId !== selected.id) return post;
      return {
        ...post,
        date: selectedDate,
        time: selectedTime,
        status: "Scheduled",
        platforms: platforms.length ? platforms : ["Facebook"],
        scheduledBy: "Facebook Calendar day planner"
      };
    });
    saveCalendarQueue(next);
    window.BoltKitToast?.("Post scheduled on the Facebook calendar.");
  };

  const dateKey = (date) => {
    const safe = date instanceof Date && !Number.isNaN(date.getTime()) ? date : new Date();
    return `${safe.getFullYear()}-${String(safe.getMonth() + 1).padStart(2, "0")}-${String(safe.getDate()).padStart(2, "0")}`;
  };

  const moveMonth = (delta) => {
    const next = new Date(visibleMonth.getFullYear(), visibleMonth.getMonth() + delta, 1, 12);
    setVisibleMonth(next);
    setSelectedDate(dateKey(next));
  };

  const moveDay = (delta) => {
    const next = new Date(`${selectedDate}T12:00:00`);
    next.setDate(next.getDate() + delta);
    setSelectedDate(dateKey(next));
    setVisibleMonth(new Date(next.getFullYear(), next.getMonth(), 1, 12));
  };

  const jumpToday = () => {
    const today = new Date();
    const next = new Date(today.getFullYear(), today.getMonth(), today.getDate(), 12);
    setSelectedDate(dateKey(next));
    setVisibleMonth(new Date(next.getFullYear(), next.getMonth(), 1, 12));
  };

  const jumpNextScheduled = () => {
    const future = posts
      .filter(post => post.date)
      .map(post => ({ post, at: scheduledAt(post) }))
      .filter(item => item.at && item.at >= new Date())
      .sort((a, b) => a.at - b.at)[0];
    if (!future) {
      window.BoltKitToast?.("No future scheduled Facebook posts yet.");
      return;
    }
    const next = dateKey(future.at);
    setSelectedDate(next);
    setSelectedPost(future.post.id);
    setVisibleMonth(new Date(future.at.getFullYear(), future.at.getMonth(), 1, 12));
  };

  const showFilterHint = () => {
    const active = platforms.length ? platforms.join(", ") : "no platforms";
    window.BoltKitToast?.(`Facebook calendar filtered to ${active}.`);
  };

  const addToCalendarFromHero = () => {
    const calIds = new Set(queuePosts.map(p => p.id));
    const unimported = draftQueue.filter(p => !calIds.has(p.id));
    if (unimported.length) { importDraftsToCalendar(); return; }
    if (queuePosts.length) { scheduleSelectedPost(); return; }
    window.BoltKitGo?.("fb-generate");
  };

  const selectedDateEvents = (eventsByDate[selectedDate] || []).sort((a, b) => String(a.post.time || "").localeCompare(String(b.post.time || "")));

  // Pull one post from next day (+1) or push last post to next day (-1), rebalancing times on both days
  const adjustDayCount = (delta) => {
    const genTimes = (n) => {
      if (n <= 0) return [];
      if (n === 1) return ["09:00"];
      const S = 8 * 60, E = 20 * 60;
      return Array.from({ length: n }, (_, i) => {
        const m = Math.round(S + (E - S) * i / (n - 1));
        return `${String(Math.floor(m / 60)).padStart(2,"0")}:${String(m % 60).padStart(2,"0")}`;
      });
    };
    const nextD = new Date(`${selectedDate}T12:00:00`);
    nextD.setDate(nextD.getDate() + 1);
    const nextDate = dateKey(nextD);
    const thisPosts = queuePosts.filter(p => p.date === selectedDate).sort((a, b) => String(a.time||"").localeCompare(String(b.time||"")));
    const nextPosts = queuePosts.filter(p => p.date === nextDate).sort((a, b) => String(a.time||"").localeCompare(String(b.time||"")));
    const otherPosts = queuePosts.filter(p => p.date !== selectedDate && p.date !== nextDate);

    if (delta > 0) {
      if (!nextPosts.length) { window.BoltKitToast?.({ msg: "No posts on the next day to pull from.", type: "error" }); return; }
      const [pulled, ...remainingNext] = nextPosts;
      const newThis = [...thisPosts, { ...pulled, date: selectedDate }];
      const updated = [
        ...otherPosts,
        ...newThis.map((p, i) => ({ ...p, date: selectedDate, time: genTimes(newThis.length)[i] })),
        ...remainingNext.map((p, i) => ({ ...p, date: nextDate, time: genTimes(remainingNext.length)[i] })),
      ];
      saveCalendarQueue(updated);
      window.BoltKitToast?.({ msg: `Pulled 1 post from ${nextDate.slice(5)} · now ${newThis.length} on ${selectedDate.slice(5)}.`, type: "success" });
    } else {
      if (!thisPosts.length) { window.BoltKitToast?.({ msg: "No posts on this day.", type: "error" }); return; }
      const remainingThis = thisPosts.slice(0, -1);
      const newNext = [{ ...thisPosts[thisPosts.length - 1], date: nextDate }, ...nextPosts];
      const updated = [
        ...otherPosts,
        ...remainingThis.map((p, i) => ({ ...p, date: selectedDate, time: genTimes(remainingThis.length)[i] })),
        ...newNext.map((p, i) => ({ ...p, date: nextDate, time: genTimes(newNext.length)[i] })),
      ];
      saveCalendarQueue(updated);
      window.BoltKitToast?.({ msg: `Pushed 1 post to ${nextDate.slice(5)} · now ${remainingThis.length} on ${selectedDate.slice(5)}.`, type: "success" });
    }
  };
  const moveFbPostToDate = (postId, newDate) => {
    const next = queuePosts.map(p => p.id !== postId ? p : { ...p, date: newDate, status: p.status || "Scheduled" });
    saveCalendarQueue(next);
    setSelectedDate(newDate);
    window.BoltKitToast?.({ msg: `Moved to ${newDate}.`, type: "success" });
  };

  const missedCount = posts.filter(isPastScheduled).length;
  const hasStartedSchedule = posts.some(post => post.scheduleStarted && !isPastScheduled(post));
  const scheduledCount = posts.filter(post => post.date && String(post.date).match(/\d{4}-\d{2}-\d{2}/)).length;
  const confirmedCount = posts.filter(post => post.scheduleStarted && !isPastScheduled(post)).length;
  const readyCount = posts.filter(post => (post.ready || post.scheduleStarted) && !isPastScheduled(post)).length;
  const draftCount = Math.max(0, posts.length - scheduledCount);
  const cardState = missedCount ? "missed" : hasStartedSchedule ? "confirmed" : scheduledCount ? "ready" : "draft";

  // Feed preview data
  const isPostedSt = s => ["Posted", "posted", "published", "sent"].includes(String(s || "").toLowerCase());
  const feedPosts = posts
    .filter(p => {
      if (feedMode === "Posted")   return isPostedSt(p.status);
      if (feedMode === "Upcoming") return !isPostedSt(p.status);
      return true;
    })
    .sort((a, b) => {
      const aAt = new Date(`${a.date || "9999-12-31"}T${a.time || "09:00"}:00Z`);
      const bAt = new Date(`${b.date || "9999-12-31"}T${b.time || "09:00"}:00Z`);
      return aAt - bAt;
    });

  return (
    <div className="ig-redesign-shell">
      <SidebarNav active="fb-calendar" />
      <main className="ig-redesign-main">
        <TopBar project="Facebook Calendar" />
        <div className="ig-redesign-scroll">
          {/* ── Hero ── */}
          <section className="ig-hero-panel">
            <div>
              <div className="ig-eyebrow"><span />FACEBOOK · PAGE CALENDAR</div>
              <h1>Facebook schedule.</h1>
              <div className="ig-status-row">
                <SyncChip state="sync" />
                <Pill tone={missedCount ? "red" : autopilotState === "on" ? "green" : scheduledCount ? "yellow" : "amber"}>
                  {missedCount ? `${missedCount} missed` : autopilotState === "on" ? "Autopilot on" : scheduledCount ? `${scheduledCount} scheduled` : "Not scheduled"}
                </Pill>
                <span style={{ color: "#5C5C5C", fontSize: 12 }}>{scheduledCount} scheduled · {draftCount} unscheduled · {missedCount} missed</span>
              </div>
            </div>
            <div className="ig-hero-actions">
              <button data-bk-bound="true" className="btn btn-secondary" onClick={() => window.BoltKitGo?.("fb-generate")}>
                <Icon name="sparkle" size={12} stroke={2} /> Generate posts
              </button>
              <button data-bk-bound="true" className="btn btn-primary" onClick={addToCalendarFromHero} disabled={scheduling}>
                <BoltMini size={13} color="#1A1813" /> {scheduling ? "Scheduling…" : "Import & schedule"}
              </button>
            </div>
          </section>

          {/* MASTER CONTROLS — posts/day + stop/clear/resume */}
          <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap", padding: "10px 0", marginBottom: 4, borderBottom: "1px solid #2C2A22" }}>
            {/* Import unscheduled drafts */}
            {(() => {
              const calIds = new Set(queuePosts.map(p => p.id));
              const unimported = draftQueue.filter(p => !calIds.has(p.id));
              return unimported.length > 0 ? (
                <button data-bk-bound="true" className="btn btn-sm" onClick={importDraftsToCalendar} disabled={scheduling}
                  style={{ background: "rgba(239,255,0,0.1)", border: "1px solid rgba(239,255,0,0.35)", color: "#EFFF00", whiteSpace: "nowrap" }}>
                  <BoltMini size={10} color="#EFFF00" /> {scheduling ? "Importing…" : `Import ${unimported.length} posts`}
                </button>
              ) : null;
            })()}
            {/* Auto-date undated */}
            {queuePosts.filter(p => !p.date || !String(p.date).match(/\d{4}-\d{2}-\d{2}/)).length > 0 && (
              <button data-bk-bound="true" className="btn btn-sm" onClick={autoDateAllPosts}
                style={{ background: "rgba(255,178,63,0.08)", border: "1px solid rgba(255,178,63,0.3)", color: "#FFB23F", whiteSpace: "nowrap" }}>
                <Icon name="calendar" size={10} stroke={2} /> Auto-date {queuePosts.filter(p => !p.date).length}
              </button>
            )}
            {/* Posts per day */}
            <div style={{ display: "flex", alignItems: "center", gap: 4, background: "#26241E", border: "1px solid #3A372F", borderRadius: 5, padding: "0 6px", height: 28 }}>
              <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, color: "#5C5C5C", letterSpacing: "0.1em", marginRight: 2 }}>POSTS/DAY</span>
              <button data-bk-bound="true" onClick={() => setImportPerDay(n => Math.max(1, n-1))} style={{ background: "none", border: "none", color: "#1877F2", cursor: "pointer", fontSize: 14, padding: "0 2px", lineHeight: 1 }}>−</button>
              <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 11, color: "#FFF", fontWeight: 700, minWidth: 18, textAlign: "center" }}>{importPerDay}</span>
              <button data-bk-bound="true" onClick={() => setImportPerDay(n => Math.min(12, n+1))} style={{ background: "none", border: "none", color: "#1877F2", cursor: "pointer", fontSize: 14, padding: "0 2px", lineHeight: 1 }}>+</button>
            </div>
            {/* Autopilot status */}
            {autopilotState === "on" ? (
              <span style={{ display: "flex", alignItems: "center", gap: 5, fontFamily: "'JetBrains Mono', monospace", fontSize: 9.5, color: "#4ADE80", fontWeight: 700, letterSpacing: "0.1em" }}>
                <span style={{ width: 7, height: 7, borderRadius: "50%", background: "#4ADE80", display: "inline-block" }} />
                AUTOPILOT RUNNING
              </span>
            ) : scheduledCount > 0 ? (
              <button data-bk-bound="true" className="btn btn-sm" style={{ background: "#EFFF00", border: "none", color: "#1A1813", fontWeight: 700 }} disabled={autopilotState === "pushing"} onClick={startServerAutopilot}>
                <BoltMini size={10} color="#1A1813" /> {autopilotState === "pushing" ? "Pushing…" : autopilotState === "error" ? "Retry" : `Push ${scheduledCount} to server`}
              </button>
            ) : null}
            <div style={{ flex: 1 }} />
            {/* Stop */}
            {autopilotState === "on" && (
              <button data-bk-bound="true" className="btn btn-sm" style={{ background: "#26241E", border: "1px solid #3A372F", color: "#FFB23F", whiteSpace: "nowrap" }} onClick={() => setAutopilotState("idle")}>
                ⏸ Stop
              </button>
            )}
            {/* Resume */}
            {autopilotState !== "on" && scheduledCount > 0 && (
              <button data-bk-bound="true" className="btn btn-sm" style={{ background: "#26241E", border: "1px solid #3A372F", color: "#4ADE80", whiteSpace: "nowrap" }} onClick={startServerAutopilot} disabled={autopilotState === "pushing"}>
                ▶ Resume
              </button>
            )}
            {/* Clear */}
            {!confirmClear ? (
              <button data-bk-bound="true" className="btn btn-sm" style={{ background: "#26241E", border: "1px solid #3A372F", color: "#FF4D5E", whiteSpace: "nowrap" }} onClick={() => setConfirmClear(true)}>
                ✕ Clear schedule
              </button>
            ) : (
              <div style={{ display: "flex", gap: 4, alignItems: "center" }}>
                <span style={{ fontSize: 11, color: "#FF4D5E", fontWeight: 600 }}>Delete all {queuePosts.filter(p => !["posted","published","sent"].includes(String(p.status||"").toLowerCase())).length} posts?</span>
                <button data-bk-bound="true" className="btn btn-sm" style={{ background: "#FF4D5E", border: "none", color: "#FFF", whiteSpace: "nowrap" }} onClick={clearFbSchedule}>Delete all</button>
                <button data-bk-bound="true" className="btn btn-sm" style={{ background: "#26241E", border: "1px solid #3A372F", color: "#A8A8A5" }} onClick={() => setConfirmClear(false)}>Cancel</button>
              </div>
            )}
          </div>

          {/* ── Missed posts — critical banner (only one that stays full-width) ── */}
          {missedCount > 0 && (
            <div style={{ margin: "12px 0", padding: "12px 16px", background: "rgba(255,77,94,0.08)", border: "1px solid rgba(255,77,94,0.35)", borderRadius: 8, display: "flex", alignItems: "center", gap: 12 }}>
              <Icon name="alert" size={14} stroke={2.4} color="#FF4D5E" />
              <span style={{ flex: 1, fontSize: 12.5, color: "#FF4D5E", fontWeight: 600 }}>{missedCount} post{missedCount !== 1 ? "s" : ""} missed their scheduled time.</span>
              <button data-bk-bound="true" className="btn btn-sm" style={{ background: "#FF4D5E", color: "#fff", border: "none", flex: "none", whiteSpace: "nowrap" }} onClick={postMissedNow}>
                Post all now · 10-min intervals
              </button>
            </div>
          )}

          <section className="social-calendar-layout">
            <div className="social-calendar-card">
              <div className="ig-panel-head">
                <div>
                  <div className="ig-eyebrow small"><span />{monthLabel}</div>
                  <h2>{calendarMode} calendar</h2>
                </div>
                <div className="ig-chip-row compact calendar-nav">
                  <button className="ig-pill-button square" onClick={() => moveMonth(-1)} aria-label="Previous month"><Icon name="chevron_left" size={13} stroke={2.5} /></button>
                  {["Month", "Week", "Day"].map((label) => <button key={label} className={"ig-pill-button" + (calendarMode === label ? " active" : "")} onClick={() => setCalendarMode(label)}>{label}</button>)}
                  <button className="ig-pill-button square" onClick={() => moveMonth(1)} aria-label="Next month"><Icon name="chevron_right" size={13} stroke={2.5} /></button>
                  <button className="ig-pill-button" onClick={jumpToday}>Today</button>
                  <button className="ig-pill-button" onClick={jumpNextScheduled}>Next post</button>
                </div>
              </div>
              <div className="social-week-head">
                {["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"].map(day => <span key={day}>{day}</span>)}
              </div>
              <div className="social-calendar-grid">
                {Array.from({ length: 42 }).map((_, index) => {
                  const day = index - gridOffset + 1;
                  const dim = day < 1 || day > daysInMonth;
                  const displayDate = new Date(visibleMonth.getFullYear(), visibleMonth.getMonth(), Math.max(1, Math.min(daysInMonth, day)), 12);
                  const cellDateKey = dateKey(displayDate);
                  const display = dim ? "" : day;
                  const active = cellDateKey === selectedDate && !dim;
                  const events = dim ? [] : (eventsByDate[cellDateKey] || []);
                  return (
                    <button key={index} className={(dim ? "dim " : "") + (active ? "active " : "") + (fbDragPostId && fbDragOverDate === cellDateKey && !dim ? "drop-target " : "")} onClick={() => !dim && setSelectedDate(cellDateKey)}
                      onDragOver={e => { if (dim || !fbDragPostId) return; e.preventDefault(); e.dataTransfer.dropEffect = "move"; setFbDragOverDate(cellDateKey); }}
                      onDragLeave={e => { if (e.currentTarget.contains(e.relatedTarget)) return; setFbDragOverDate(null); }}
                      onDrop={e => { e.preventDefault(); if (fbDragPostId && !dim) moveFbPostToDate(fbDragPostId, cellDateKey); setFbDragPostId(null); setFbDragOverDate(null); }}>
                      <b>{display}</b>
                      {events.slice(0, 4).map((event, eventIndex) => (
                        <span
                          key={`${event.label}-${eventIndex}`}
                          className={`${platformClass(event.platform)} ${postStageClass(event.post)}`}
                          draggable
                          onDragStart={e => { e.stopPropagation(); e.dataTransfer.effectAllowed = "move"; setFbDragPostId(event.post.id); setFbDragOverDate(null); }}
                          onDragEnd={() => { setFbDragPostId(null); setFbDragOverDate(null); }}
                          style={{ cursor: "pointer", opacity: fbDragPostId === event.post.id ? 0.35 : 1 }}
                          onClick={e => { if (!fbDragPostId) openCalPopup(e, event.post); }}
                        >{event.label} · {event.status}</span>
                      ))}
                      {events.length > 4 && <span className="platform-more" onClick={e => { e.stopPropagation(); setSelectedDate(cellDateKey); }}>+ {events.length - 4} more</span>}
                    </button>
                  );
                })}
              </div>
            </div>

            <aside className="day-planner-panel">
              <div className="ig-eyebrow small"><span />DAY PLANNER</div>
              <div className="calendar-day-nav">
                <button className="ig-pill-button square" onClick={() => moveDay(-1)} aria-label="Previous day"><Icon name="chevron_left" size={13} stroke={2.5} /></button>
                <h2>{new Date(`${selectedDate}T12:00:00`).toLocaleDateString("en-GB", { weekday: "short", day: "numeric", month: "short" })}</h2>
                <button className="ig-pill-button square" onClick={() => moveDay(1)} aria-label="Next day"><Icon name="chevron_right" size={13} stroke={2.5} /></button>
              </div>
              {/* Posts-per-day adjuster — pull from / push to next day */}
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "6px 0 8px", marginBottom: 6, borderBottom: "1px solid #2C2A22" }}>
                <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 9, color: "#5C5C5C", letterSpacing: "0.12em" }}>
                  {selectedDateEvents.length} POST{selectedDateEvents.length !== 1 ? "S" : ""} · ADJUST DAY
                </span>
                <div style={{ display: "flex", alignItems: "center", gap: 2 }}>
                  <button data-bk-bound="true" onClick={() => adjustDayCount(-1)} title="Push last post to next day" style={{ width: 22, height: 22, borderRadius: 4, background: "#26241E", border: "1px solid #3A372F", color: "#A8A8A5", cursor: "pointer", fontSize: 14, display: "flex", alignItems: "center", justifyContent: "center", lineHeight: 1 }}>−</button>
                  <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 10, fontWeight: 700, color: "#FFF", minWidth: 20, textAlign: "center" }}>{selectedDateEvents.length}</span>
                  <button data-bk-bound="true" onClick={() => adjustDayCount(1)} title="Pull one post from next day" style={{ width: 22, height: 22, borderRadius: 4, background: "#26241E", border: "1px solid #3A372F", color: "#A8A8A5", cursor: "pointer", fontSize: 14, display: "flex", alignItems: "center", justifyContent: "center", lineHeight: 1 }}>+</button>
                </div>
              </div>
              <div className="calendar-day-events">
                {selectedDateEvents.length ? selectedDateEvents.map((event, index) => (
                  <button key={`${event.label}-${index}`} className={`${platformClass(event.platform)} ${postStageClass(event.post)}`} onClick={() => setSelectedPost(event.post.id)}>
                    <b>{event.platform}</b>
                    <span>{event.post.label}</span>
                    <small>{event.post.time || "09:00"} · {postStage(event.post)}</small>
                  </button>
                )) : <p>No Facebook posts scheduled for this day yet.</p>}
              </div>

              {/* Post picker — visual thumbnails */}
              <div>
                <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8, letterSpacing: "0.14em", color: "#5C5C5C", marginBottom: 6 }}>SELECT POST</div>
                <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 5, maxHeight: 180, overflowY: "auto" }}>
                  {posts.map(post => {
                    const isSel = post.id === selectedPost;
                    const img = post.imageUrl || post.publicUrl;
                    const isSchd = Boolean(post.date);
                    return (
                      <button key={post.id} data-bk-bound="true" onClick={() => setSelectedPost(post.id)}
                        style={{
                          position: "relative", aspectRatio: "4/5", borderRadius: 5, overflow: "hidden",
                          border: `2px solid ${isSel ? "#EFFF00" : isSchd ? "#4ADE80" : "#3A372F"}`,
                          background: "#1A1813", cursor: "pointer", padding: 0,
                        }}>
                        {img
                          ? <img src={img} alt="" style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }} />
                          : <div style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}><BoltMini size={12} color="#3A372F" /></div>}
                        {isSchd && (
                          <div style={{ position: "absolute", bottom: 0, left: 0, right: 0, background: "rgba(74,222,128,0.85)", fontFamily: "'JetBrains Mono', monospace", fontSize: 7, color: "#0a1a0a", fontWeight: 800, padding: "2px 3px", textAlign: "center" }}>
                            {post.date?.slice(5)}
                          </div>
                        )}
                        {isSel && (
                          <div style={{ position: "absolute", top: 3, right: 3, width: 12, height: 12, borderRadius: "50%", background: "#EFFF00", display: "flex", alignItems: "center", justifyContent: "center" }}>
                            <Icon name="check" size={7} stroke={3} color="#1A1813" />
                          </div>
                        )}
                      </button>
                    );
                  })}
                </div>
              </div>

              <div className="selected-post-preview">
                <div><BoltMini size={18} color="#1A1813" /></div>
                <section>
                  <b>{selected ? selected.label : "No post selected"}</b>
                  <span>{selected ? `${selected.type} · ${postStage(selected)}` : "Select a post from the thumbnails above"}</span>
                </section>
              </div>
              <label>
                <span>Time</span>
                <input type="time" value={time} onChange={(event) => setTime(event.target.value)} />
              </label>
              <button className="btn btn-primary" style={{ width: "100%", justifyContent: "center" }} onClick={scheduleSelectedPost}>
                <Icon name="calendar" size={12} stroke={2} /> Schedule on Facebook
              </button>
              <button
                data-bk-bound="true"
                className="btn btn-secondary"
                style={{ width: "100%", justifyContent: "center", marginTop: 6, borderColor: fbAccount ? "#4ADE80" : "#3A372F", color: fbAccount ? "#4ADE80" : "#5C5C5C" }}
                onClick={() => selected && publishNow(selected)}
                disabled={!fbAccount || publishingId === selected?.id}
              >
                {publishingId === selected?.id
                  ? <><span className="bolt-thinking" style={{ display: "inline-block", lineHeight: 0 }}><BoltMini size={11} color="#EFFF00" /></span> Publishing…</>
                  : <><Icon name="facebook" size={12} stroke={2} /> Publish now</>}
              </button>
              {!fbAccount && (
                <button data-bk-bound="true" onClick={() => window.BoltKitGo?.("fb-connect")} style={{ marginTop: 8, fontFamily: "'JetBrains Mono', monospace", fontSize: 9, color: "#EFFF00", letterSpacing: "0.1em", fontWeight: 700, background: "none", border: "none", cursor: "pointer", padding: 0, width: "100%", textAlign: "center" }}>
                  CONNECT FACEBOOK PAGE →
                </button>
              )}
            </aside>
          </section>

          {/* ── Facebook Feed Preview ───────────────────────────────────── */}
          <section style={{ marginTop: 36, paddingBottom: 48 }}>
            <div className="ig-panel-head" style={{ marginBottom: 20 }}>
              <div>
                <div className="ig-eyebrow small"><span />FACEBOOK FEED PREVIEW</div>
                <h2>How your posts will look on Facebook</h2>
              </div>
              <div className="ig-chip-row compact">
                {["All", "Upcoming", "Posted"].map(m => (
                  <button key={m} className={"ig-pill-button" + (feedMode === m ? " active" : "")} onClick={() => setFeedMode(m)}>
                    {m} {m === "Upcoming" ? `(${posts.filter(p => !isPostedSt(p.status)).length})` : m === "Posted" ? `(${posts.filter(p => isPostedSt(p.status)).length})` : `(${posts.length})`}
                  </button>
                ))}
              </div>
            </div>

            {feedPosts.length === 0 ? (
              <div style={{ textAlign: "center", padding: "48px 24px", border: "1px dashed #2C2A22", borderRadius: 12 }}>
                <Icon name="facebook" size={32} stroke={1.5} color="#3A3B3C" />
                <p style={{ marginTop: 14, color: "#5C5C5C", fontSize: 14 }}>
                  {feedMode === "Posted" ? "No posts published yet." : feedMode === "Upcoming" ? "No upcoming posts scheduled." : "No posts yet — generate some content first."}
                </p>
                <button data-bk-bound="true" className="btn btn-secondary btn-sm" style={{ marginTop: 10 }} onClick={() => window.BoltKitGo?.("fb-generate")}>
                  <Icon name="sparkle" size={11} stroke={2} /> Generate posts
                </button>
              </div>
            ) : (
              <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", gap: 18 }}>
                {feedPosts.map(post => (
                  <FbPostCard
                    key={post.id}
                    post={post}
                    onPublish={publishNow}
                    publishingId={publishingId}
                    fbAccount={fbAccount}
                  />
                ))}
              </div>
            )}
          </section>

        </div>
      </main>

      {/* Calendar block popup — Edit / Delete / Move */}
      {calPopup && (
        <>
          <div onClick={() => setCalPopup(null)} style={{ position: "fixed", inset: 0, zIndex: 9990 }} />
          <div style={{
            position: "fixed", left: calPopup.x, top: calPopup.y, width: 296, zIndex: 9999,
            background: "#1E1C16", border: "1px solid #3A372F", borderRadius: 10,
            boxShadow: "0 10px 40px rgba(0,0,0,0.6)", overflow: "hidden",
          }}>
            {/* Header */}
            <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "12px 14px 10px", borderBottom: "1px solid #2C2A22" }}>
              {(calPopup.post.imageUrl || calPopup.post.publicUrl) && (
                <img src={calPopup.post.imageUrl || calPopup.post.publicUrl} alt="" style={{ width: 40, height: 40, objectFit: "cover", borderRadius: 5, flex: "none" }} />
              )}
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 9, letterSpacing: "0.12em", color: "#EFFF00", fontWeight: 800, marginBottom: 2 }}>FACEBOOK POST</div>
                <div style={{ fontSize: 11.5, color: "#CCC", fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{calPopup.post.label || "Untitled"}</div>
              </div>
              <button onClick={() => setCalPopup(null)} style={{ background: "none", border: "none", color: "#5C5C5C", cursor: "pointer", fontSize: 16, lineHeight: 1, padding: 2 }}>✕</button>
            </div>

            {/* Fields */}
            <div style={{ padding: "12px 14px", display: "flex", flexDirection: "column", gap: 10 }}>
              <label style={{ display: "flex", flexDirection: "column", gap: 4 }}>
                <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, letterSpacing: "0.12em", color: "#5C5C5C", fontWeight: 700 }}>CAPTION</span>
                <textarea
                  value={calPopup.post.caption || ""}
                  onChange={e => updateCalPopupField("caption", e.target.value)}
                  rows={3}
                  style={{ background: "#141210", border: "1px solid #3A372F", borderRadius: 5, color: "#E0E0E0", fontSize: 11.5, padding: "7px 9px", resize: "vertical", fontFamily: "inherit", lineHeight: 1.5 }}
                />
              </label>
              <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
                <label style={{ display: "flex", flexDirection: "column", gap: 4 }}>
                  <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, letterSpacing: "0.12em", color: "#5C5C5C", fontWeight: 700 }}>DATE (MOVE)</span>
                  <input
                    type="date"
                    value={calPopup.post.date || ""}
                    onChange={e => updateCalPopupField("date", e.target.value)}
                    style={{ background: "#141210", border: "1px solid #3A372F", borderRadius: 5, color: "#E0E0E0", fontSize: 11, padding: "6px 8px", fontFamily: "'JetBrains Mono', monospace" }}
                  />
                </label>
                <label style={{ display: "flex", flexDirection: "column", gap: 4 }}>
                  <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, letterSpacing: "0.12em", color: "#5C5C5C", fontWeight: 700 }}>TIME</span>
                  <input
                    type="time"
                    value={calPopup.post.time || "09:00"}
                    onChange={e => updateCalPopupField("time", e.target.value)}
                    style={{ background: "#141210", border: "1px solid #3A372F", borderRadius: 5, color: "#E0E0E0", fontSize: 11, padding: "6px 8px", fontFamily: "'JetBrains Mono', monospace" }}
                  />
                </label>
              </div>
            </div>

            {/* Actions */}
            <div style={{ padding: "0 14px 14px", display: "flex", gap: 8 }}>
              <button onClick={deleteCalPopup} style={{ flex: "none", background: "rgba(255,77,94,0.12)", border: "1px solid rgba(255,77,94,0.3)", color: "#FF4D5E", borderRadius: 6, padding: "7px 12px", fontSize: 11.5, cursor: "pointer", fontWeight: 600 }}>
                Delete
              </button>
              <button onClick={saveCalPopup} style={{ flex: 1, background: "#EFFF00", border: "none", color: "#1A1813", borderRadius: 6, padding: "7px 12px", fontSize: 11.5, cursor: "pointer", fontWeight: 700 }}>
                <BoltMini size={11} color="#1A1813" /> Save changes
              </button>
            </div>
          </div>
        </>
      )}
    </div>
  );
};

let FacebookPublishDashboard = () => {
  const loadQueue = () => { try { return JSON.parse(localStorage.getItem("boltkit.fbPosts.v1") || "[]"); } catch { return []; } };
  const [queuePosts,      setQueuePosts]      = React.useState(loadQueue);
  const [publishing,      setPublishing]      = React.useState(false);
  const [currentlyPosting,setCurrentlyPosting]= React.useState(null);
  const [publishErrors,   setPublishErrors]   = React.useState([]);
  const [pageInfo,        setPageInfo]        = React.useState(null); // { name, id } from diag
  const [pageConnected,   setPageConnected]   = React.useState(null); // null=loading, true/false
  const [now,             setNow]             = React.useState(new Date());
  const [autoPostEnabled, setAutoPostEnabled] = React.useState(true);
  const [showBulk,        setShowBulk]        = React.useState(false);
  const [confirmClear,    setConfirmClear]    = React.useState(false);
  const [postStory,       setPostStory]       = React.useState(() => { try { return JSON.parse(localStorage.getItem("boltkit.fbPostStory") || "false"); } catch { return false; } });
  const publishingRef = React.useRef(false);

  // Second-by-second clock
  React.useEffect(() => {
    const t = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(t);
  }, []);

  // Poll localStorage for queue changes
  React.useEffect(() => {
    const sync = () => setQueuePosts(loadQueue());
    window.addEventListener("boltkit:saved", sync);
    const t = setInterval(sync, 5000);
    return () => { window.removeEventListener("boltkit:saved", sync); clearInterval(t); };
  }, []);

  // Facebook page connection check via diag endpoint
  React.useEffect(() => {
    fetch("/api/facebook-diag")
      .then(r => r.json())
      .then(d => {
        if (d.error) { setPageConnected(false); return; }
        const page = d.pages_returned?.[0] || (d.configured_page_id ? { id: d.configured_page_id, name: "Facebook Page" } : null);
        if (page) { setPageInfo(page); setPageConnected(true); }
        else setPageConnected(false);
      })
      .catch(() => setPageConnected(false));
  }, []);

  const saveQueue = (next) => {
    setQueuePosts(next);
    try { localStorage.setItem("boltkit.fbPosts.v1", JSON.stringify(next)); } catch {}
    window.dispatchEvent(new Event("boltkit:saved"));
  };

  const autoPublish = React.useCallback(async (post) => {
    if (publishingRef.current) return;
    publishingRef.current = true;
    setPublishing(true);
    setCurrentlyPosting(post);
    window.BoltKitToast?.({ msg: "Auto-posting to Facebook…", type: "loading" });
    const mediaUrl = post.publicUrl || post.imageUrl;
    try {
      const hashtags = Array.isArray(post.hashtags) ? post.hashtags.map(h => h.startsWith("#") ? h : `#${h}`).join(" ") : (post.hashtags || "");
      const captionText = [post.hook, post.caption, hashtags].filter(Boolean).join("\n\n");
      const resp = await fetch("/api/facebook-publish-now", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ mediaUrl, caption: captionText, mediaType: "IMAGE" }),
      });
      const data = await resp.json();
      if (data.ok && !data.skipped) {
        const queue = loadQueue();
        const next = queue.map(p => p.id === post.id
          ? { ...p, status: "Posted", postedAt: new Date().toISOString(), fbPostId: data.post_id || null }
          : p
        );
        saveQueue(next);
        window.BoltKitToast?.({ msg: "Posted to Facebook!", type: "success" });
      } else if (data.skipped) {
        setPublishErrors(prev => [...prev, { post, error: "Publishing disabled — set ENABLE_FACEBOOK_PUBLISHING=true in Vercel", time: new Date() }]);
        window.BoltKitToast?.({ msg: "Publishing is disabled in Vercel.", type: "error" });
      } else {
        setPublishErrors(prev => [...prev, { post, error: data.error || "Publish failed", time: new Date() }]);
        window.BoltKitToast?.({ msg: data.error || "Publish failed.", type: "error" });
      }
    } catch (err) {
      setPublishErrors(prev => [...prev, { post, error: err.message || "Network error", time: new Date() }]);
      window.BoltKitToast?.({ msg: "Publish error: " + err.message, type: "error" });
    }
    publishingRef.current = false;
    setPublishing(false);
    setCurrentlyPosting(null);
  }, []);

  // Auto-post engine — checks every 30s
  React.useEffect(() => {
    if (!autoPostEnabled) return;
    const check = () => {
      if (publishingRef.current) return;
      const queue = loadQueue();
      const nowMs = Date.now();
      const due = queue.find(p => {
        if (!p.date) return false;
        const at = new Date(`${p.date}T${p.time || "09:00"}:00Z`).getTime();
        const s = String(p.status || "").toLowerCase();
        const url = p.publicUrl || p.imageUrl;
        return at <= nowMs && !["posted", "published", "sent", "failed"].includes(s) && url && !url.startsWith("blob:") && !url.startsWith("data:");
      });
      if (due) autoPublish(due);
    };
    check();
    const t = setInterval(check, 30000);
    return () => clearInterval(t);
  }, [autoPostEnabled, autoPublish]);

  const retryPost = async (errItem) => {
    setPublishErrors(prev => prev.filter(e => e !== errItem));
    await autoPublish(errItem.post);
  };

  // ── Sync status from Supabase ─────────────────────────────────────────────
  // Vercel cron posts without the browser open. On return, pull server
  // statuses and merge into the local queue so "Posted" badges are accurate.
  React.useEffect(() => {
    const syncFromServer = async () => {
      try {
        const proj = (() => { try { return JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch { return {}; } })();
        const resp = await fetch("/api/supabase-facebook-posts", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ action: "load", project: proj }),
        });
        const data = await resp.json();
        if (!data.ok || !Array.isArray(data.posts) || !data.posts.length) return;
        const serverMap = {};
        for (const p of data.posts) serverMap[p.id] = p;
        const local = loadQueue();
        const normalise = s => {
          const l = (s || "").toLowerCase();
          if (l === "published" || l === "posted" || l === "sent") return "Posted";
          if (l === "failed") return "Failed";
          if (l === "publishing") return "Scheduled";
          return null;
        };
        let changed = false;
        const merged = local.map(p => {
          const sv = serverMap[p.id];
          if (!sv) return p;
          const norm = normalise(sv.status);
          if (norm && norm !== p.status) { changed = true; return { ...p, status: norm }; }
          return p;
        });
        if (changed) saveQueue(merged);
      } catch {}
    };
    syncFromServer();
    const t = setInterval(syncFromServer, 2 * 60 * 1000); // every 2 min
    return () => clearInterval(t);
  }, []);

  // Reschedule all unposted posts from the next available slot (2/day · 9am & 6pm)
  const rescheduleFromNow = async () => {
    const PER_DAY = 2;
    const TIMES = ["09:00", "18:00"];
    const all = loadQueue();
    const posted = all.filter(p => isPosted(p.status));
    const unposted = all.filter(p => !isPosted(p.status));
    if (!unposted.length) {
      window.BoltKitToast?.({ msg: "No unposted posts to reschedule.", type: "success" }); return;
    }
    // Find the next future slot
    const nowD = new Date();
    const pad = n => String(n).padStart(2, "0");
    const dKey = d => `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`;
    const todayKey = dKey(nowD);
    let startDayOffset = 0;
    let startTimeIdx = 0;
    // Try today's slots first
    let foundToday = false;
    for (let ti = 0; ti < TIMES.length; ti++) {
      const [h, m] = TIMES[ti].split(":").map(Number);
      const slot = new Date(nowD.getFullYear(), nowD.getMonth(), nowD.getDate(), h, m, 0);
      if (slot > nowD) { startTimeIdx = ti; startDayOffset = 0; foundToday = true; break; }
    }
    if (!foundToday) { startDayOffset = 1; startTimeIdx = 0; }
    const rescheduled = unposted.map((post, i) => {
      const absSlot = startTimeIdx + i;
      const dayOff = startDayOffset + Math.floor(absSlot / PER_DAY);
      const timeIdx = absSlot % PER_DAY;
      const d = new Date(nowD.getFullYear(), nowD.getMonth(), nowD.getDate() + dayOff);
      return { ...post, date: dKey(d), time: TIMES[timeIdx], status: "Scheduled" };
    });
    const merged = [...posted, ...rescheduled];
    saveQueue(merged);
    const firstDate = rescheduled[0]?.date || todayKey;
    window.BoltKitToast?.({ msg: `${unposted.length} posts rescheduled from ${firstDate} — pushing to server…`, type: "loading" });
    try {
      let proj = {};
      try { proj = JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch {}
      const resp = await fetch("/api/supabase-facebook-posts", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action: "save", project: proj, posts: merged }),
      });
      const data = await resp.json();
      if (data.ok) {
        window.BoltKitToast?.({ msg: `${unposted.length} posts rescheduled from ${firstDate} — live on server ✓`, type: "success" });
      } else {
        throw new Error(data.error || "Save failed");
      }
    } catch (err) {
      window.BoltKitToast?.({ msg: "Rescheduled locally but server push failed: " + err.message, type: "error" });
    }
  };

  // Move an upcoming post up (-1) or down (+1) by swapping its time-slot with its neighbour
  const moveUpcoming = async (id, dir) => {
    const all = loadQueue();
    const isPst = s => ["Posted", "posted", "published", "sent"].includes(String(s || "").toLowerCase());
    const sorted = all
      .filter(p => p.date && !isPst(p.status) && new Date(`${p.date}T${p.time || "09:00"}:00Z`) > new Date())
      .sort((a, b) => new Date(`${a.date}T${a.time || "09:00"}:00Z`) - new Date(`${b.date}T${b.time || "09:00"}:00Z`));
    const idx = sorted.findIndex(p => p.id === id);
    const swapIdx = idx + dir;
    if (idx < 0 || swapIdx < 0 || swapIdx >= sorted.length) return;
    const aSlot = { date: sorted[idx].date,      time: sorted[idx].time      || "09:00" };
    const bSlot = { date: sorted[swapIdx].date,  time: sorted[swapIdx].time  || "09:00" };
    const next = all.map(p => {
      if (p.id === sorted[idx].id)     return { ...p, date: bSlot.date, time: bSlot.time };
      if (p.id === sorted[swapIdx].id) return { ...p, date: aSlot.date, time: aSlot.time };
      return p;
    });
    saveQueue(next);
    try {
      let proj = {};
      try { proj = JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch {}
      await fetch("/api/supabase-facebook-posts", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action: "save", project: proj, posts: next }),
      });
    } catch {}
  };

  // Remove a single post from the FB queue
  const removePost = async (id) => {
    const next = loadQueue().filter(p => p.id !== id);
    saveQueue(next);
    try {
      let proj = {};
      try { proj = JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch {}
      await fetch("/api/supabase-facebook-posts", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action: "save", project: proj, posts: next }),
      });
    } catch {}
  };

  // Toggle "also post as story" — updates all queued posts + syncs to server
  const toggleStory = async () => {
    const next = !postStory;
    setPostStory(next);
    localStorage.setItem("boltkit.fbPostStory", JSON.stringify(next));
    const all = loadQueue();
    const updated = all.map(p => isPosted(p.status) ? p : { ...p, also_story: next });
    saveQueue(updated);
    try {
      let proj = {};
      try { proj = JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch {}
      await fetch("/api/supabase-facebook-posts", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action: "save", project: proj, posts: updated }),
      });
    } catch {}
  };

  // Clear all unposted FB posts
  const clearUnposted = async () => {
    const next = loadQueue().filter(p => isPosted(p.status));
    saveQueue(next);
    try {
      let proj = {};
      try { proj = JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch {}
      await fetch("/api/supabase-facebook-posts", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action: "save", project: proj, posts: next }),
      });
    } catch {}
    setConfirmClear(false);
  };

  // Post all missed FB posts now in 10-minute intervals
  const postMissedNow = async () => {
    const all = loadQueue();
    const isPst = s => ["Posted", "posted", "published", "sent"].includes(String(s || "").toLowerCase());
    const missed = all.filter(p => {
      if (!p.date || isPst(p.status)) return false;
      return new Date(`${p.date}T${p.time || "09:00"}:00Z`) <= new Date();
    });
    if (!missed.length) return;
    const base = new Date();
    const pad = n => String(n).padStart(2, "0");
    const dStr = d => `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`;
    const tStr = d => `${pad(d.getHours())}:${pad(d.getMinutes())}`;
    const rescheduled = missed.map((p, i) => {
      const slot = new Date(base.getTime() + (i + 1) * 10 * 60 * 1000);
      return { ...p, date: dStr(slot), time: tStr(slot), status: "Scheduled" };
    });
    const next = all.map(p => rescheduled.find(r => r.id === p.id) || p);
    saveQueue(next);
    window.BoltKitToast?.({ msg: `${missed.length} missed post${missed.length !== 1 ? "s" : ""} rescheduled — firing in 10-min intervals from now.`, type: "success" });
    try {
      let proj = {};
      try { proj = JSON.parse(localStorage.getItem("boltkit.currentProject.v1") || "{}"); } catch {}
      await fetch("/api/supabase-facebook-posts", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ action: "save", project: proj, posts: next }),
      });
    } catch {}
  };

  // Derived state
  // Case-insensitive: rowToPost capitalises first letter ("Published"), UI sets "Posted"
  const isPosted = s => ["posted", "published", "sent"].includes(String(s || "").toLowerCase());
  const postedPosts   = queuePosts.filter(p => isPosted(p.status)).sort((a, b) => new Date(b.postedAt || 0) - new Date(a.postedAt || 0));
  const missedPosts   = queuePosts.filter(p => {
    if (!p.date || isPosted(p.status)) return false;
    return new Date(`${p.date}T${p.time || "09:00"}:00Z`) <= now;
  });
  const upcomingPosts = queuePosts.filter(p => {
    if (!p.date) return false;
    const at = new Date(`${p.date}T${p.time || "09:00"}:00Z`);
    return at > now && !isPosted(p.status);
  }).sort((a, b) => new Date(`${a.date}T${a.time || "09:00"}:00Z`) - new Date(`${b.date}T${b.time || "09:00"}:00Z`));

  const nextPost = upcomingPosts[0];
  const nextAt   = nextPost ? new Date(`${nextPost.date}T${nextPost.time || "09:00"}:00Z`) : null;
  const secsUntilNext = nextAt ? Math.max(0, Math.floor((nextAt - now) / 1000)) : null;

  const fmtCountdown = (secs) => {
    if (secs === null) return "—";
    if (secs === 0)    return "NOW";
    const d = Math.floor(secs / 86400);
    const h = Math.floor((secs % 86400) / 3600);
    const m = Math.floor((secs % 3600) / 60);
    const s = secs % 60;
    if (d > 0) return `${d}d ${h}h ${String(m).padStart(2,"0")}m`;
    if (h > 0) return `${h}h ${String(m).padStart(2,"0")}m ${String(s).padStart(2,"0")}s`;
    return `${String(m).padStart(2,"0")}m ${String(s).padStart(2,"0")}s`;
  };

  const etaLabel = (secs) => {
    if (secs < 3600)  return `${Math.floor(secs / 60)}m`;
    if (secs < 86400) return `${Math.floor(secs / 3600)}h`;
    return `${Math.floor(secs / 86400)}d`;
  };

  const isLive     = autoPostEnabled && !!nextPost && pageConnected;
  const dashStatus = publishing ? "POSTING" : publishErrors.length ? "ERROR" : isLive ? "LIVE" : "IDLE";

  return (
    <div className="ig-redesign-shell">
      <SidebarNav active="fb-live" />
      <main className="ig-redesign-main">
        <TopBar project="SHIFT · Facebook Live Feed" />
        <div className="ig-redesign-scroll">

          {/* Hero */}
          <section className="ig-hero-panel">
            <div>
              <div className="ig-eyebrow"><span />FACEBOOK · LIVE PUBLISHING</div>
              <h1>Facebook live feed.</h1>
              <p>What's posted, what's coming up, and what fires next. Auto-post checks every 30 seconds — the moment a post's time arrives it goes straight to your Facebook Page.</p>
              <div className="ig-status-row">
                <span className={"publish-status-badge publish-status-" + dashStatus.toLowerCase()}>
                  <span className="publish-pulse" />
                  {dashStatus}
                </span>
                {pageConnected === null
                  ? <Pill tone="dark">Checking…</Pill>
                  : pageConnected
                    ? <Pill tone="green">{pageInfo?.name || "Facebook Page"} · connected</Pill>
                    : <Pill tone="amber">Facebook Page not connected</Pill>}
                <span>{postedPosts.length} posted · {upcomingPosts.length} upcoming · {missedPosts.length > 0 ? `${missedPosts.length} missed · ` : ""}{publishErrors.length} error{publishErrors.length !== 1 ? "s" : ""}</span>
              </div>
            </div>
            <div className="ig-hero-actions">
              <button data-bk-bound="true" className="btn btn-secondary" onClick={() => window.BoltKitGo?.("fb-calendar")}>
                <Icon name="calendar" size={12} stroke={2} /> Calendar
              </button>
              <button data-bk-bound="true" className="btn btn-secondary" onClick={() => window.BoltKitGo?.("fb-generate")}>
                <Icon name="sparkle" size={12} stroke={2} /> Generate
              </button>
            </div>
          </section>

          {/* Missed posts banner */}
          {missedPosts.length > 0 && (
            <div style={{ display: "flex", alignItems: "center", gap: 14, padding: "14px 18px", background: "rgba(255,77,94,0.07)", border: "1px solid rgba(255,77,94,0.3)", borderRadius: 10, flexWrap: "wrap" }}>
              <Icon name="alert" size={18} stroke={2.4} color="#FF4D5E" />
              <div style={{ flex: 1, minWidth: 0 }}>
                <b style={{ fontSize: 13, color: "#FF4D5E", display: "block" }}>
                  {missedPosts.length} post{missedPosts.length !== 1 ? "s" : ""} missed {missedPosts.length === 1 ? "its" : "their"} scheduled time
                </b>
                <span style={{ fontSize: 11.5, color: "#8A8A8A" }}>
                  They were skipped because the browser wasn't open or the engine was paused. Post them now in 10-minute intervals.
                </span>
              </div>
              <button className="btn btn-primary btn-sm" style={{ flex: "none", whiteSpace: "nowrap", background: "#FF4D5E", borderColor: "#FF4D5E" }} onClick={postMissedNow}>
                <Icon name="signal" size={11} stroke={2} /> Post all {missedPosts.length} now · 10-min intervals
              </button>
            </div>
          )}

          {/* Currently posting banner */}
          {publishing && currentlyPosting && (
            <div className="publish-now-card">
              <div className="publish-now-anim">
                <span className="publish-radar" />
                <span className="publish-radar-2" />
                <BoltMini size={22} color="#1A1813" />
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div className="ig-eyebrow small" style={{ marginBottom: 4 }}><span />POSTING NOW</div>
                <b>{currentlyPosting.title || (currentlyPosting.caption || "").slice(0, 60) || "Post"}</b>
                <span>Sending to Facebook {pageInfo?.name ? `· ${pageInfo.name}` : ""}…</span>
              </div>
              {(currentlyPosting.publicUrl || currentlyPosting.imageUrl) && !/^(blob:|data:)/.test(currentlyPosting.publicUrl || currentlyPosting.imageUrl) && (
                <img src={currentlyPosting.publicUrl || currentlyPosting.imageUrl} alt="" className="publish-now-thumb" />
              )}
            </div>
          )}

          {/* Stats strip */}
          <div className="publish-stats-strip">
            <div className="publish-stat">
              <b>{postedPosts.length}</b>
              <span>Posted</span>
            </div>
            <div className="publish-stat">
              <b>{upcomingPosts.length}</b>
              <span>Upcoming</span>
            </div>
            <div className={"publish-stat" + (secsUntilNext !== null ? " accent" : "")}>
              <b>{fmtCountdown(secsUntilNext)}</b>
              <span>Next post</span>
            </div>
            <div className="publish-stat">
              <b>{queuePosts.length}</b>
              <span>Total posts</span>
            </div>
            <div className="publish-stat">
              <b>{queuePosts.filter(p => p.date && !isPosted(p.status)).length}</b>
              <span>Scheduled</span>
            </div>
            <div className={"publish-stat" + (publishErrors.length ? " publish-status-error" : "")}>
              <b style={publishErrors.length ? { color: "#FF4D5E" } : {}}>{publishErrors.length}</b>
              <span>Errors</span>
            </div>
          </div>

          {/* Main grid */}
          <div className="publish-main-grid">

            {/* Left — Posted feed */}
            <div>
              <div className="publish-feed-col">
                <div className="publish-feed-header">
                  <div>
                    <div className="card-title">Posted</div>
                    <div className="card-sub">Published to your Facebook Page</div>
                  </div>
                  <Pill tone={postedPosts.length ? "green" : "dark"}>{postedPosts.length}</Pill>
                </div>
                {postedPosts.length ? postedPosts.map(post => {
                  const img = post.publicUrl || post.imageUrl;
                  return (
                    <div key={post.id} className="publish-posted-row">
                      {img && !/^(blob:|data:)/.test(img)
                        ? <img src={img} alt="" className="publish-row-thumb" />
                        : <div className="publish-row-thumb publish-row-thumb-empty"><BoltMini size={12} color="#3A372F" /></div>}
                      <div className="publish-row-body">
                        <b>{post.title || (post.caption || "").slice(0, 55) || "Post"}</b>
                        <span>{post.postedAt ? new Date(post.postedAt).toLocaleString("en-GB", { day: "numeric", month: "short", hour: "2-digit", minute: "2-digit" }) : (post.date || "—")}</span>
                        {post.fbPostId && (
                          <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, color: "#5C5C5C", letterSpacing: "0.08em" }}>
                            ID: {post.fbPostId}
                          </span>
                        )}
                      </div>
                      <div className="publish-row-eng">
                        <Icon name="facebook" size={11} stroke={2} color="#5C5C5C" />
                      </div>
                      <Pill tone="green">Posted</Pill>
                    </div>
                  );
                }) : (
                  <div className="ig-empty-queue" style={{ padding: 32 }}>
                    <Icon name="signal" size={28} stroke={1.5} color="#3A372F" />
                    <b>Nothing posted yet.</b>
                    <span>Posts appear here as they go live. Auto-post is {autoPostEnabled ? "on and watching" : "currently off"}.</span>
                  </div>
                )}
              </div>
            </div>

            {/* Right — Next post + upcoming + errors + controls */}
            <div className="publish-right-col">

              {/* Next post */}
              {nextPost ? (
                <div className="publish-next-card">
                  <div className="ig-eyebrow small"><span />NEXT POST</div>
                  <div className="publish-countdown">{fmtCountdown(secsUntilNext)}</div>
                  <div className="publish-next-details">
                    <b>{nextPost.title || (nextPost.caption || "").slice(0, 55) || "Scheduled post"}</b>
                    <span>{nextPost.date} at {nextPost.time || "09:00"}</span>
                  </div>
                  {(nextPost.publicUrl || nextPost.imageUrl) && !/^(blob:|data:)/.test(nextPost.publicUrl || nextPost.imageUrl) && (
                    <img src={nextPost.publicUrl || nextPost.imageUrl} alt="" className="publish-next-thumb" />
                  )}
                  <button
                    className="btn btn-secondary"
                    style={{ width: "100%", justifyContent: "center", marginTop: 12 }}
                    disabled={publishing || !pageConnected}
                    onClick={() => autoPublish(nextPost)}
                  >
                    <Icon name="facebook" size={12} stroke={2} /> Post now to Facebook
                  </button>
                </div>
              ) : (
                <div className="publish-next-card">
                  <div className="ig-eyebrow small"><span />NEXT POST</div>
                  <div className="publish-countdown" style={{ color: "#3A372F" }}>—</div>
                  <div className="publish-next-details">
                    <b style={{ color: "#5C5C5C" }}>No upcoming posts</b>
                    <span>Schedule posts in the Facebook Calendar to see them here</span>
                  </div>
                  <button data-bk-bound="true" className="btn btn-secondary btn-sm" style={{ width: "100%", justifyContent: "center", marginTop: 12 }} onClick={() => window.BoltKitGo?.("fb-generate")}>
                    <Icon name="sparkle" size={12} stroke={2} /> Generate posts
                  </button>
                </div>
              )}

              {/* Upcoming list — reorderable */}
              <div className="publish-upcoming-section">
                <div className="ig-panel-head" style={{ marginBottom: 8 }}>
                  <div>
                    <div className="card-title">Coming up</div>
                    <div className="card-sub" style={{ fontSize: 10.5, marginTop: 2 }}>Use ↑↓ to change order — slots reassign automatically</div>
                  </div>
                  <Pill tone={upcomingPosts.length ? "yellow" : "dark"}>{upcomingPosts.length}</Pill>
                </div>
                {upcomingPosts.length ? upcomingPosts.map((post, idx) => {
                  const at   = new Date(`${post.date}T${post.time || "09:00"}:00Z`);
                  const secs = Math.max(0, Math.floor((at - now) / 1000));
                  const img  = post.publicUrl || post.imageUrl;
                  const isFirst = idx === 0;
                  const isLast  = idx === upcomingPosts.length - 1;
                  return (
                    <div key={post.id} className="publish-upcoming-row" style={{ gap: 6 }}>
                      {/* Reorder controls */}
                      <div style={{ display: "flex", flexDirection: "column", gap: 2, flex: "none" }}>
                        <button
                          onClick={() => moveUpcoming(post.id, -1)}
                          disabled={isFirst}
                          style={{ background: "none", border: "1px solid #3A372F", borderRadius: 3, width: 18, height: 17, display: "flex", alignItems: "center", justifyContent: "center", cursor: isFirst ? "default" : "pointer", opacity: isFirst ? 0.2 : 0.7, padding: 0, color: "#FFF" }}
                          title="Move earlier"
                        >
                          <Icon name="chevron_down" size={9} stroke={2.5} style={{ transform: "rotate(180deg)", display: "block" }} />
                        </button>
                        <button
                          onClick={() => moveUpcoming(post.id, 1)}
                          disabled={isLast}
                          style={{ background: "none", border: "1px solid #3A372F", borderRadius: 3, width: 18, height: 17, display: "flex", alignItems: "center", justifyContent: "center", cursor: isLast ? "default" : "pointer", opacity: isLast ? 0.2 : 0.7, padding: 0, color: "#FFF" }}
                          title="Move later"
                        >
                          <Icon name="chevron_down" size={9} stroke={2.5} />
                        </button>
                      </div>
                      {/* Thumbnail */}
                      {img && !/^(blob:|data:)/.test(img)
                        ? <img src={img} alt="" style={{ width: 30, height: 38, objectFit: "cover", borderRadius: 3, flex: "none", border: "1px solid #3A372F" }} />
                        : <div style={{ width: 30, height: 38, background: "#2C2A23", borderRadius: 3, flex: "none", display: "flex", alignItems: "center", justifyContent: "center" }}><BoltMini size={9} color="#5C5C5C" /></div>}
                      {/* Info */}
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div className="publish-upcoming-label">{post.title || (post.caption || "").slice(0, 38) || "Post"}</div>
                        <div className="publish-upcoming-meta">{post.date} · {post.time || "09:00"}</div>
                      </div>
                      {/* ETA */}
                      <div className="publish-upcoming-eta">{etaLabel(secs)}</div>
                      {/* Remove */}
                      <button
                        onClick={() => removePost(post.id)}
                        title="Remove from queue"
                        style={{ background: "none", border: "none", color: "#3A372F", cursor: "pointer", fontSize: 14, padding: "0 2px", lineHeight: 1, flex: "none", transition: "color 0.15s" }}
                        onMouseEnter={e => e.currentTarget.style.color = "#FF4D5E"}
                        onMouseLeave={e => e.currentTarget.style.color = "#3A372F"}
                      >✕</button>
                    </div>
                  );
                }) : (
                  <p style={{ fontSize: 12, color: "#5C5C5C", margin: 0 }}>No upcoming posts. Schedule in the <button data-bk-bound="true" style={{ background: "none", border: "none", color: "#EFFF00", cursor: "pointer", fontSize: 12, padding: 0 }} onClick={() => window.BoltKitGo?.("fb-calendar")}>Facebook Calendar</button>.</p>
                )}
              </div>

              {/* Errors */}
              {publishErrors.length > 0 && (
                <div className="publish-error-panel">
                  <div><Icon name="alert" size={14} stroke={2.5} color="#FF4D5E" />{publishErrors.length} ERROR{publishErrors.length !== 1 ? "S" : ""}</div>
                  {publishErrors.map((err, i) => (
                    <div key={i} className="publish-error-row">
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontSize: 11.5, color: "#FF4D5E", fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                          {err.post.title || (err.post.caption || "").slice(0, 40) || "Post"}
                        </div>
                        <div style={{ fontSize: 10.5, color: "#8A8A8A", marginTop: 2, lineHeight: 1.4 }}>{err.error}</div>
                      </div>
                      <button className="btn btn-secondary btn-sm" style={{ flex: "none" }} onClick={() => retryPost(err)}>Retry</button>
                    </div>
                  ))}
                  <button className="btn btn-ghost btn-sm" style={{ marginTop: 8 }} onClick={() => setPublishErrors([])}>Clear all</button>
                </div>
              )}

              {/* Campaign Control */}
              <div className="publish-engine-card">
                <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, color: "#5C5C5C", letterSpacing: "0.14em", marginBottom: 12 }}>CAMPAIGN CONTROL</div>

                {/* Status row */}
                <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 14 }}>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 3 }}>
                      <span style={{ width: 8, height: 8, borderRadius: "50%", background: isLive ? "#4ADE80" : autoPostEnabled ? "#FFB23F" : "#5C5C5C", display: "inline-block", ...(isLive ? { animation: "pub-pulse-dot 1.4s infinite" } : {}) }} />
                      <span style={{ fontFamily: "'Anton', Impact, sans-serif", fontSize: 20, color: isLive ? "#4ADE80" : autoPostEnabled ? "#FFB23F" : "#8A8A8A", lineHeight: 1, letterSpacing: "0.02em" }}>
                        {isLive ? "RUNNING" : autoPostEnabled ? (pageConnected ? "WATCHING" : "WAITING") : "PAUSED"}
                      </span>
                    </div>
                    <div style={{ fontSize: 11, color: "#5C5C5C" }}>
                      {upcomingPosts.length} post{upcomingPosts.length !== 1 ? "s" : ""} queued · {postedPosts.length} posted
                    </div>
                  </div>
                  <button
                    onClick={() => { setAutoPostEnabled(v => !v); setConfirmClear(false); }}
                    title={autoPostEnabled ? "Pause campaign" : "Resume campaign"}
                    style={{ width: 50, height: 50, borderRadius: 12, border: autoPostEnabled ? "2px solid #3A372F" : "none", background: autoPostEnabled ? "#26241E" : "#EFFF00", color: autoPostEnabled ? "#8A8A8A" : "#1A1813", display: "flex", alignItems: "center", justifyContent: "center", cursor: "pointer", flex: "none", fontSize: 22 }}
                  >
                    {autoPostEnabled ? "⏸" : "▶"}
                  </button>
                </div>

                {pageConnected === false && (
                  <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 10, padding: "8px 10px", background: "rgba(255,178,63,0.08)", borderRadius: 6, border: "1px solid rgba(255,178,63,0.2)" }}>
                    <span style={{ width: 5, height: 5, borderRadius: "50%", background: "#FFB23F", display: "inline-block", flex: "none" }} />
                    <span style={{ fontSize: 10.5, color: "#FFB23F", lineHeight: 1.5 }}>
                      Facebook Page not connected. <button data-bk-bound="true" style={{ background: "none", border: "none", color: "#EFFF00", cursor: "pointer", fontSize: 10.5, padding: 0 }} onClick={() => window.BoltKitGo?.("fb-connect")}>Connect Page →</button>
                    </span>
                  </div>
                )}

                <div style={{ display: "flex", flexDirection: "column", gap: 6, paddingTop: 12, borderTop: "1px solid #2C2A22" }}>
                  {/* Story toggle */}
                  <div
                    onClick={toggleStory}
                    style={{ display: "flex", alignItems: "center", gap: 10, padding: "9px 12px", background: postStory ? "rgba(239,255,0,0.06)" : "#26241E", borderRadius: 8, cursor: "pointer", border: postStory ? "1px solid rgba(239,255,0,0.2)" : "1px solid transparent", transition: "all 0.2s" }}
                  >
                    <div style={{ width: 36, height: 20, borderRadius: 10, background: postStory ? "#EFFF00" : "#3A372F", position: "relative", flex: "none", transition: "background 0.2s" }}>
                      <div style={{ width: 14, height: 14, borderRadius: "50%", background: postStory ? "#1A1813" : "#5C5C5C", position: "absolute", top: 3, left: postStory ? 18 : 3, transition: "left 0.2s" }} />
                    </div>
                    <div style={{ minWidth: 0 }}>
                      <div style={{ fontSize: 12, fontWeight: 600, color: postStory ? "#FFF" : "#8A8A8A", lineHeight: 1.2 }}>Also post as Story</div>
                      <div style={{ fontSize: 10, color: "#5C5C5C", marginTop: 1 }}>Reposts each image as a Facebook Story simultaneously</div>
                    </div>
                  </div>

                  <button className="btn btn-primary btn-sm" style={{ width: "100%", justifyContent: "center" }} onClick={() => setShowBulk(true)}>
                    <Icon name="calendar" size={11} stroke={2} /> Bulk Schedule
                  </button>
                  <button className="btn btn-secondary btn-sm" style={{ width: "100%", justifyContent: "center" }} onClick={rescheduleFromNow}>
                    <Icon name="refresh" size={11} stroke={2} /> Quick reschedule (2/day)
                  </button>
                  {!confirmClear
                    ? <button
                        className="btn btn-ghost btn-sm"
                        style={{ width: "100%", justifyContent: "center", color: upcomingPosts.length ? "#FF4D5E" : "#3A372F", borderColor: upcomingPosts.length ? "rgba(255,77,94,0.3)" : "#2C2A22" }}
                        onClick={() => setConfirmClear(true)}
                        disabled={!upcomingPosts.length}
                      >
                        <Icon name="trash" size={11} stroke={2} /> Clear queue ({upcomingPosts.length})
                      </button>
                    : <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
                        <button
                          className="btn btn-ghost btn-sm"
                          style={{ width: "100%", justifyContent: "center", background: "rgba(255,77,94,0.12)", color: "#FF4D5E", border: "1px solid rgba(255,77,94,0.5)", fontWeight: 700 }}
                          onClick={clearUnposted}
                        >
                          Confirm — delete all {upcomingPosts.length} unposted
                        </button>
                        <button className="btn btn-ghost btn-sm" style={{ width: "100%", justifyContent: "center" }} onClick={() => setConfirmClear(false)}>Cancel</button>
                      </div>
                  }
                </div>
              </div>
            </div>
          </div>
        </div>
      </main>
      {showBulk && (
        <BulkScheduleModal
          posts={queuePosts}
          storageKey="boltkit.fbPosts.v1"
          apiEndpoint="/api/supabase-facebook-posts"
          postStory={postStory}
          onClose={() => { setShowBulk(false); setQueuePosts(loadQueue()); }}
        />
      )}
    </div>
  );
};

/* ── BulkScheduleModal — shared by IG and FB publish dashboards ────────── */
const BulkScheduleModal = ({ posts, storageKey, apiEndpoint, postStory, onClose }) => {
  const isPst = s => ["Posted", "posted", "published", "sent"].includes(String(s || "").toLowerCase());
  const unposted = posts.filter(p => !isPst(p.status)).slice(0, 500);
  const total = unposted.length;

  const genTimes = (n) => {
    if (n <= 0) return [];
    if (n === 1) return ["09:00"];
    const start = 7 * 60, end = 22 * 60;
    const step = (end - start) / (n - 1);
    return Array.from({ length: n }, (_, i) => {
      const m = Math.round(start + i * step);
      return `${String(Math.floor(m / 60)).padStart(2, "0")}:${String(m % 60).padStart(2, "0")}`;
    });
  };

  const todayPlus1 = () => { const d = new Date(); d.setDate(d.getDate() + 1); return d.toISOString().split("T")[0]; };

  const [postsPerDay, setPostsPerDay] = React.useState(2);
  const [times,       setTimes]       = React.useState(["09:00", "18:00"]);
  const [startDate,   setStartDate]   = React.useState(todayPlus1());
  const [newTime,     setNewTime]     = React.useState("12:00");
  const [confirming,  setConfirming]  = React.useState(false);
  const [applying,    setApplying]    = React.useState(false);

  const sortedTimes = [...times].sort();
  const daysNeeded  = postsPerDay > 0 ? Math.ceil(total / postsPerDay) : 0;

  const endDate = (() => {
    if (!daysNeeded || !startDate) return "—";
    const d = new Date(startDate + "T00:00:00");
    d.setDate(d.getDate() + daysNeeded - 1);
    return d.toISOString().split("T")[0];
  })();

  const setPerDay = (n) => {
    const c = Math.max(1, Math.min(20, n));
    setPostsPerDay(c);
    setTimes(genTimes(c));
  };

  const removeTime = (i) => {
    const next = times.filter((_, idx) => idx !== i);
    if (!next.length) return;
    setTimes(next);
    setPostsPerDay(next.length);
  };

  const addTime = () => {
    if (!newTime || times.includes(newTime)) return;
    const next = [...times, newTime].sort();
    setTimes(next);
    setPostsPerDay(next.length);
  };

  const editTime = (i, val) => {
    const next = [...times];
    next[i] = val;
    setTimes(next);
  };

  const apply = async () => {
    if (!sortedTimes.length || applying) return;
    setApplying(true);
    try {
      const all = (() => { try { return JSON.parse(localStorage.getItem(storageKey) || "[]"); } catch { return []; } })();
      const posted    = all.filter(p => isPst(p.status));
      const toSlot    = all.filter(p => !isPst(p.status)).slice(0, 500);
      const start     = new Date(startDate + "T00:00:00");
      let slotIdx = 0, dayOffset = 0;
      const rescheduled = toSlot.map(post => {
        const slotTime = sortedTimes[slotIdx];
        const d = new Date(start);
        d.setDate(d.getDate() + dayOffset);
        const dateStr = d.toISOString().split("T")[0];
        slotIdx++;
        if (slotIdx >= sortedTimes.length) { slotIdx = 0; dayOffset++; }
        return { ...post, date: dateStr, time: slotTime, status: "pending", also_story: !!postStory };
      });
      const next = [...posted, ...rescheduled];
      localStorage.setItem(storageKey, JSON.stringify(next));
      window.dispatchEvent(new Event("boltkit:saved"));
      if (apiEndpoint) {
        try { await fetch(apiEndpoint, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ posts: next }) }); } catch {}
      }
    } catch {}
    setApplying(false);
    onClose();
  };

  const inp = { background: "#26241E", border: "1px solid #3A372F", borderRadius: 6, padding: "7px 10px", color: "#FFF", fontFamily: "'JetBrains Mono', monospace", fontSize: 13, outline: "none", width: "100%", boxSizing: "border-box" };

  return (
    <div style={{ position: "fixed", inset: 0, zIndex: 9000, display: "flex", alignItems: "center", justifyContent: "center", background: "rgba(0,0,0,0.76)", backdropFilter: "blur(6px)" }}
      onClick={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div style={{ background: "#1A1813", border: "1px solid #3A372F", borderRadius: 14, width: 440, maxWidth: "94vw", maxHeight: "92vh", overflowY: "auto", padding: 26, display: "flex", flexDirection: "column", gap: 20 }}>

        {/* Header */}
        <div style={{ display: "flex", alignItems: "flex-start" }}>
          <div style={{ flex: 1 }}>
            <div style={{ fontFamily: "'Anton', Impact, sans-serif", fontSize: 24, color: "#FFF", lineHeight: 1, letterSpacing: "0.02em" }}>BULK SCHEDULE</div>
            <div style={{ fontSize: 12, color: "#8A8A8A", marginTop: 5, lineHeight: 1.5 }}>
              Clear all unposted posts and re-slot up to 200 from scratch with your chosen cadence.
            </div>
          </div>
          <button onClick={onClose} style={{ background: "none", border: "none", color: "#5C5C5C", cursor: "pointer", fontSize: 20, padding: "0 0 0 12px", lineHeight: 1 }}>✕</button>
        </div>

        {/* Posts per day */}
        <div>
          <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, color: "#5C5C5C", letterSpacing: "0.14em", marginBottom: 12 }}>POSTS PER DAY</div>
          <div style={{ display: "flex", alignItems: "center", gap: 16 }}>
            <button onClick={() => setPerDay(postsPerDay - 1)} style={{ width: 40, height: 40, borderRadius: 8, background: "#26241E", border: "1px solid #3A372F", color: "#FFF", fontSize: 22, cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", flex: "none" }}>−</button>
            <div style={{ flex: 1, textAlign: "center" }}>
              <div style={{ fontFamily: "'Anton', Impact, sans-serif", fontSize: 44, color: "#EFFF00", lineHeight: 1 }}>{postsPerDay}</div>
              <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8, color: "#5C5C5C", letterSpacing: "0.12em", marginTop: 2 }}>PER DAY</div>
            </div>
            <button onClick={() => setPerDay(postsPerDay + 1)} style={{ width: 40, height: 40, borderRadius: 8, background: "#26241E", border: "1px solid #3A372F", color: "#FFF", fontSize: 22, cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", flex: "none" }}>+</button>
          </div>
        </div>

        {/* Posting times */}
        <div>
          <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, color: "#5C5C5C", letterSpacing: "0.14em", marginBottom: 10 }}>POSTING TIMES</div>
          <div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
            {times.map((t, i) => (
              <div key={i} style={{ display: "flex", alignItems: "center", gap: 8 }}>
                <span style={{ fontSize: 11, color: "#EFFF00", flex: "none", lineHeight: 1 }}>○</span>
                <input type="time" value={t} onChange={e => editTime(i, e.target.value)} style={{ ...inp, flex: 1, width: "auto" }} />
                <button onClick={() => removeTime(i)} disabled={times.length <= 1}
                  style={{ background: "none", border: "none", color: times.length <= 1 ? "#3A372F" : "#5C5C5C", cursor: times.length <= 1 ? "default" : "pointer", fontSize: 16, padding: "0 4px", flex: "none" }}>✕</button>
              </div>
            ))}
          </div>
          <div style={{ display: "flex", gap: 8, marginTop: 10 }}>
            <input type="time" value={newTime} onChange={e => setNewTime(e.target.value)} style={{ ...inp, flex: 1, width: "auto" }} />
            <button onClick={addTime} className="btn btn-ghost btn-sm" style={{ flex: "none", whiteSpace: "nowrap" }}>+ Add time</button>
          </div>
        </div>

        {/* Start date */}
        <div>
          <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, color: "#5C5C5C", letterSpacing: "0.14em", marginBottom: 10 }}>START DATE</div>
          <input type="date" value={startDate} onChange={e => setStartDate(e.target.value)} style={inp} />
        </div>

        {/* Preview */}
        <div style={{ background: "#26241E", borderRadius: 10, padding: "14px 16px" }}>
          <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, color: "#5C5C5C", letterSpacing: "0.14em", marginBottom: 8 }}>PREVIEW</div>
          {total === 0 ? (
            <div style={{ fontSize: 13, color: "#5C5C5C" }}>No unposted posts found.</div>
          ) : (
            <>
              <div style={{ fontSize: 14, color: "#FFF", fontWeight: 700 }}>
                {total} post{total !== 1 ? "s" : ""} → {daysNeeded} day{daysNeeded !== 1 ? "s" : ""}
              </div>
              <div style={{ fontSize: 11, color: "#8A8A8A", marginTop: 4, lineHeight: 1.6 }}>
                Starts {startDate} · ends {endDate}<br />
                {postsPerDay}/day at {sortedTimes.join(", ")}
              </div>
            </>
          )}
        </div>

        {/* Warning */}
        <div style={{ background: "rgba(255,77,94,0.07)", border: "1px solid rgba(255,77,94,0.22)", borderRadius: 8, padding: "10px 14px", fontSize: 12, color: "#FF4D5E", lineHeight: 1.6 }}>
          ⚠ This will clear and re-slot all {total} unposted post{total !== 1 ? "s" : ""}. Already-posted content is untouched.
        </div>

        {/* Actions */}
        <div style={{ display: "flex", gap: 10 }}>
          <button className="btn btn-ghost" style={{ flex: 1 }} onClick={onClose}>Cancel</button>
          {!confirming
            ? <button className="btn btn-primary" style={{ flex: 2 }} onClick={() => setConfirming(true)} disabled={total === 0 || !sortedTimes.length}>
                Clear &amp; Reschedule
              </button>
            : <button className="btn btn-primary" style={{ flex: 2, background: "#FF4D5E", borderColor: "#FF4D5E", color: "#FFF" }} onClick={apply} disabled={applying}>
                {applying ? "Applying…" : `Confirm — reschedule ${total} posts`}
              </button>
          }
        </div>
        {confirming && !applying && (
          <p style={{ textAlign: "center", fontSize: 11, color: "#FF4D5E", margin: "-12px 0 0", lineHeight: 1.5 }}>
            Click confirm to apply. This cannot be undone.
          </p>
        )}
      </div>
    </div>
  );
};
window.BulkScheduleModal = BulkScheduleModal;

/* ── SocialPlatformCard — standalone so it can hold its own drag state ── */
const SocialPlatformCard = ({ label, ico, st, connected, handle, route, accent, storageKey, apiEndpoint, now, fmt }) => {
  const [dragIdx,     setDragIdx]     = React.useState(null);
  const [dragOverIdx, setDragOverIdx] = React.useState(null);

  const isPst = s => ["Posted", "posted", "published", "sent"].includes(String(s || "").toLowerCase());

  const handleDrop = (toIdx) => {
    if (dragIdx === null || dragIdx === toIdx) { setDragIdx(null); setDragOverIdx(null); return; }
    try {
      const all = JSON.parse(localStorage.getItem(storageKey) || "[]");
      const upcoming = all
        .filter(p => p.date && !isPst(p.status) && new Date(`${p.date}T${p.time || "09:00"}:00Z`) > now)
        .sort((a, b) => new Date(`${a.date}T${a.time || "09:00"}:00Z`) - new Date(`${b.date}T${b.time || "09:00"}:00Z`));
      const fromPost = upcoming[dragIdx];
      const toPost   = upcoming[toIdx];
      if (!fromPost || !toPost) { setDragIdx(null); setDragOverIdx(null); return; }
      const [aDate, aTime] = [fromPost.date, fromPost.time];
      const [bDate, bTime] = [toPost.date,   toPost.time];
      const next = all.map(p => {
        if (p.id === fromPost.id) return { ...p, date: bDate, time: bTime };
        if (p.id === toPost.id)   return { ...p, date: aDate, time: aTime };
        return p;
      });
      localStorage.setItem(storageKey, JSON.stringify(next));
      window.dispatchEvent(new Event("boltkit:saved"));
      if (apiEndpoint) {
        fetch(apiEndpoint, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ posts: next }) }).catch(() => {});
      }
    } catch {}
    setDragIdx(null);
    setDragOverIdx(null);
  };

  return (
    <div style={{ background: "#1E1C17", border: `1px solid ${accent}22`, borderRadius: 12, padding: 20, display: "flex", flexDirection: "column", gap: 16 }}>
      {/* Header */}
      <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
        <div style={{ width: 32, height: 32, borderRadius: 8, background: `${accent}18`, display: "flex", alignItems: "center", justifyContent: "center", flex: "none" }}>
          <Icon name={ico} size={16} stroke={2} color={accent} />
        </div>
        <div>
          <div style={{ fontWeight: 700, fontSize: 13, color: "#FFF" }}>{label}</div>
          <div style={{ display: "flex", alignItems: "center", gap: 5, marginTop: 1 }}>
            <span style={{ width: 5, height: 5, borderRadius: "50%", background: connected === null ? "#5C5C5C" : connected ? "#4ADE80" : "#FF4D5E", display: "inline-block" }} />
            <span style={{ fontSize: 10, color: "#8A8A8A" }}>
              {connected === null ? "Checking…" : connected ? (handle || "Connected") : "Not connected"}
            </span>
          </div>
        </div>
        <button className="btn btn-ghost btn-sm" style={{ marginLeft: "auto", fontSize: 10, padding: "3px 8px" }} onClick={() => window.BoltKitGo?.(route)}>
          Full feed →
        </button>
      </div>

      {/* Countdown */}
      <div style={{ padding: "14px 16px", background: "#26241E", borderRadius: 10 }}>
        <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, color: "#5C5C5C", letterSpacing: "0.14em", marginBottom: 4 }}>NEXT POST IN</div>
        <div style={{ fontFamily: "'Anton', Impact, sans-serif", fontSize: 34, lineHeight: 1, color: st.secs !== null ? "#FFF" : "#3A372F" }}>{fmt(st.secs)}</div>
        {st.next && <div style={{ fontSize: 11, color: "#5C5C5C", marginTop: 4 }}>{st.next.date} · {st.next.time || "09:00"} — {(st.next.title || st.next.caption || "Post").slice(0, 40)}</div>}
      </div>

      {/* Stats */}
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 8 }}>
        {[["Posted", st.posted.length, "#4ADE80"], ["Upcoming", st.upcoming.length, accent], ["Total", st.total, "#8A8A8A"]].map(([l, v, c]) => (
          <div key={l} style={{ background: "#26241E", borderRadius: 8, padding: "10px 6px", textAlign: "center" }}>
            <div style={{ fontFamily: "'Anton', Impact, sans-serif", fontSize: 24, lineHeight: 1, color: c }}>{v}</div>
            <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 7.5, color: "#5C5C5C", letterSpacing: "0.1em", marginTop: 3 }}>{l.toUpperCase()}</div>
          </div>
        ))}
      </div>

      {/* Coming up — draggable */}
      {st.upcoming.length > 0 && (
        <div>
          <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 8 }}>
            <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, color: "#5C5C5C", letterSpacing: "0.14em" }}>COMING UP</span>
            <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 7.5, color: "#3A372F", letterSpacing: "0.08em" }}>· drag to reorder</span>
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 5 }}>
            {st.upcoming.slice(0, 5).map((post, i) => {
              const at  = new Date(`${post.date}T${post.time || "09:00"}:00Z`);
              const s2  = Math.max(0, Math.floor((at - now) / 1000));
              const img = post.publicUrl || post.imageUrl;
              const isDragging = dragIdx === i;
              const isOver     = dragOverIdx === i && dragIdx !== i;
              return (
                <div
                  key={post.id}
                  draggable
                  onDragStart={e => { e.dataTransfer.effectAllowed = "move"; setDragIdx(i); }}
                  onDragOver={e => { e.preventDefault(); e.dataTransfer.dropEffect = "move"; setDragOverIdx(i); }}
                  onDragLeave={() => setDragOverIdx(null)}
                  onDrop={e => { e.preventDefault(); handleDrop(i); }}
                  onDragEnd={() => { setDragIdx(null); setDragOverIdx(null); }}
                  style={{
                    display: "flex", alignItems: "center", gap: 8, padding: "6px 8px",
                    background: isOver ? `${accent}20` : (i === 0 ? `${accent}12` : "#26241E"),
                    borderRadius: 6,
                    border: isOver ? `1px solid ${accent}60` : (i === 0 ? `1px solid ${accent}30` : "1px solid transparent"),
                    opacity: isDragging ? 0.35 : 1,
                    cursor: "grab",
                    transition: "background 0.1s, border-color 0.1s, opacity 0.15s",
                    userSelect: "none",
                  }}
                >
                  <span style={{ fontSize: 12, color: "#3A372F", flex: "none", lineHeight: 1, cursor: "grab" }}>⠿</span>
                  <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8, color: "#5C5C5C", minWidth: 12, textAlign: "center" }}>{i + 1}</span>
                  {img && !/^(blob:|data:)/.test(img)
                    ? <img src={img} alt="" style={{ width: 26, height: 26, objectFit: "cover", borderRadius: 4, flex: "none" }} />
                    : <div style={{ width: 26, height: 26, background: "#3A372F", borderRadius: 4, flex: "none" }} />}
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 11.5, color: "#E4E6EB", fontWeight: i === 0 ? 700 : 500, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                      {post.title || (post.caption || "").slice(0, 36) || "Post"}
                    </div>
                    <div style={{ fontSize: 9.5, color: "#5C5C5C" }}>{post.date} · {post.time || "09:00"}</div>
                  </div>
                  <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 9, color: i === 0 ? accent : "#5C5C5C", flex: "none", fontWeight: i === 0 ? 700 : 400 }}>{fmt(s2)}</div>
                </div>
              );
            })}
            {st.upcoming.length > 5 && (
              <div style={{ textAlign: "center", fontSize: 10, color: "#5C5C5C", padding: "2px 0" }}>+ {st.upcoming.length - 5} more scheduled</div>
            )}
          </div>
        </div>
      )}

      {/* Recently posted thumbnails */}
      {st.posted.length > 0 && (
        <div>
          <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, color: "#5C5C5C", letterSpacing: "0.14em", marginBottom: 8 }}>RECENTLY POSTED</div>
          <div style={{ display: "flex", gap: 6 }}>
            {st.posted.slice(0, 4).map(post => {
              const img = post.publicUrl || post.imageUrl;
              return (
                <div key={post.id} style={{ flex: 1, position: "relative", aspectRatio: "1", borderRadius: 6, overflow: "hidden", background: "#26241E", minWidth: 0 }}>
                  {img && !/^(blob:|data:)/.test(img)
                    ? <img src={img} alt="" style={{ width: "100%", height: "100%", objectFit: "cover", display: "block" }} />
                    : <div style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center" }}><BoltMini size={10} color="#3A372F" /></div>}
                  <div style={{ position: "absolute", bottom: 0, left: 0, right: 0, background: "rgba(74,222,128,0.88)", fontFamily: "'JetBrains Mono', monospace", fontSize: 6.5, fontWeight: 800, color: "#0a1a0a", padding: "2px 3px", textAlign: "center", letterSpacing: "0.05em" }}>✓</div>
                </div>
              );
            })}
          </div>
        </div>
      )}

      {/* Empty state */}
      {st.total === 0 && (
        <div style={{ textAlign: "center", padding: "12px 0", color: "#5C5C5C", fontSize: 12 }}>
          No posts yet — <button data-bk-bound="true" style={{ background: "none", border: "none", color: "#EFFF00", cursor: "pointer", fontSize: 12, padding: 0 }} onClick={() => window.BoltKitGo?.("fb-generate")}>generate some</button>
        </div>
      )}
    </div>
  );
};

/* ── Social Overview — both platforms on one screen ───────────────────── */
let SocialOverviewScreen = () => {
  const [now,         setNow]         = React.useState(new Date());
  const [igPosts,     setIgPosts]     = React.useState([]);
  const [fbPosts,     setFbPosts]     = React.useState([]);
  const [igConn,      setIgConn]      = React.useState(null);
  const [fbConn,      setFbConn]      = React.useState(null);
  const [igUsername,  setIgUsername]  = React.useState(null);
  const [fbPageName,  setFbPageName]  = React.useState(null);

  React.useEffect(() => {
    const t = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(t);
  }, []);

  const reload = () => {
    try { setIgPosts(JSON.parse(localStorage.getItem("boltkit.scheduledPosts.v1") || "[]")); } catch {}
    try { setFbPosts(JSON.parse(localStorage.getItem("boltkit.fbPosts.v1") || "[]")); } catch {}
  };
  React.useEffect(() => {
    reload();
    const t = setInterval(reload, 10000);
    window.addEventListener("boltkit:saved", reload);
    return () => { clearInterval(t); window.removeEventListener("boltkit:saved", reload); };
  }, []);

  React.useEffect(() => {
    fetch("/api/meta/status").then(r => r.json()).then(d => {
      if (d.accounts?.[0]) { setIgConn(true); setIgUsername(d.accounts[0].username); }
      else setIgConn(false);
    }).catch(() => setIgConn(false));
    fetch("/api/facebook-diag").then(r => r.json()).then(d => {
      const page = d.pages_returned?.[0] || (d.configured_page_id ? { name: "Facebook Page" } : null);
      if (page) { setFbConn(true); setFbPageName(page.name); }
      else setFbConn(false);
    }).catch(() => setFbConn(false));
  }, []);

  const isPostedSt = s => ["Posted", "posted", "published", "sent"].includes(String(s || "").toLowerCase());

  const stats = (posts) => {
    const posted = posts.filter(p => isPostedSt(p.status))
      .sort((a, b) => new Date(b.postedAt || 0) - new Date(a.postedAt || 0));
    const upcoming = posts.filter(p => p.date && !isPostedSt(p.status) && new Date(`${p.date}T${p.time || "09:00"}:00Z`) > now)
      .sort((a, b) => new Date(`${a.date}T${a.time || "09:00"}:00Z`) - new Date(`${b.date}T${b.time || "09:00"}:00Z`));
    const next = upcoming[0] || null;
    const nextAt = next ? new Date(`${next.date}T${next.time || "09:00"}:00Z`) : null;
    const secs = nextAt ? Math.max(0, Math.floor((nextAt - now) / 1000)) : null;
    return { posted, upcoming, next, secs, total: posts.length };
  };

  const igStats = stats(igPosts);
  const fbStats = stats(fbPosts);

  const fmt = (secs) => {
    if (secs === null) return "—";
    if (secs === 0) return "NOW";
    const d = Math.floor(secs / 86400), h = Math.floor((secs % 86400) / 3600), m = Math.floor((secs % 3600) / 60), s = secs % 60;
    if (d > 0) return `${d}d ${h}h`;
    if (h > 0) return `${h}h ${String(m).padStart(2,"0")}m`;
    return `${String(m).padStart(2,"0")}m ${String(s).padStart(2,"0")}s`;
  };

  // Overall next post across both platforms
  const allNextCandidates = [
    igStats.next && { ...igStats.next, platform: "Instagram", secs: igStats.secs },
    fbStats.next && { ...fbStats.next, platform: "Facebook",  secs: fbStats.secs },
  ].filter(Boolean).sort((a, b) => a.secs - b.secs);
  const globalNext = allNextCandidates[0] || null;

  return (
    <div className="ig-redesign-shell">
      <SidebarNav active="social-overview" />
      <main className="ig-redesign-main">
        <TopBar project="Social Overview" />
        <div className="ig-redesign-scroll">

          {/* Hero */}
          <section className="ig-hero-panel">
            <div>
              <div className="ig-eyebrow"><span />SOCIAL MEDIA OVERVIEW</div>
              <h1>All platforms, one screen.</h1>
              <p>Instagram and Facebook — queues, countdowns, and post history side by side.</p>
              <div className="ig-status-row">
                <Pill tone={(igStats.upcoming.length + fbStats.upcoming.length) > 0 ? "green" : "dark"}>
                  {igStats.upcoming.length + fbStats.upcoming.length} queued across both platforms
                </Pill>
                <span>{igStats.posted.length + fbStats.posted.length} total posted</span>
              </div>
            </div>
            <div className="ig-hero-actions">
              <button data-bk-bound="true" className="btn btn-secondary" onClick={() => window.BoltKitGo?.("fb-generate")}>
                <Icon name="sparkle" size={12} stroke={2} /> Generate
              </button>
              <button data-bk-bound="true" className="btn btn-primary" onClick={() => window.BoltKitGo?.("publish")}>
                <Icon name="signal" size={12} stroke={2} /> Live feeds
              </button>
            </div>
          </section>

          {/* Global next-post banner */}
          {globalNext && (
            <div style={{ display: "flex", alignItems: "center", gap: 16, padding: "14px 18px", background: "rgba(239,255,0,0.06)", border: "1px solid rgba(239,255,0,0.22)", borderRadius: 10, marginBottom: 4 }}>
              <div style={{ width: 34, height: 34, borderRadius: "50%", background: "#EFFF00", display: "flex", alignItems: "center", justifyContent: "center", flex: "none", animation: "pub-breathe 2s ease-in-out infinite" }}>
                <BoltMini size={19} color="#1A1813" />
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 8.5, color: "#EFFF00", letterSpacing: "0.14em", fontWeight: 800 }}>
                  NEXT — {globalNext.platform.toUpperCase()}
                </div>
                <div style={{ fontFamily: "'Anton', Impact, sans-serif", fontSize: 26, color: "#FFF", lineHeight: 1.1 }}>{fmt(globalNext.secs)}</div>
                <div style={{ fontSize: 11, color: "#8A8A8A", marginTop: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {globalNext.title || (globalNext.caption || "").slice(0, 60) || "Scheduled post"} · {globalNext.date} at {globalNext.time || "09:00"}
                </div>
              </div>
            </div>
          )}

          {/* Platform cards — side by side */}
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16, alignItems: "start" }}>
            <SocialPlatformCard label="Instagram" ico="insta"    st={igStats} connected={igConn} handle={igUsername ? `@${igUsername}` : null} route="publish" accent="#E1306C" storageKey="boltkit.scheduledPosts.v1" apiEndpoint="/api/supabase-scheduled-posts" now={now} fmt={fmt} />
            <SocialPlatformCard label="Facebook"  ico="facebook" st={fbStats} connected={fbConn} handle={fbPageName}                          route="fb-live" accent="#1877F2" storageKey="boltkit.fbPosts.v1"        apiEndpoint="/api/supabase-facebook-posts"   now={now} fmt={fmt} />
          </div>

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

Object.assign(window, { FacebookCalendarScreen, FacebookPublishDashboard, SocialOverviewScreen });
