// ───────────────────────────────────────────────────────────────
// Busco Ops — In-app guided tour
// Spotlight walkthrough of the main screens. Role-aware: each step
// declares which tab it belongs to, and only steps the signed-in
// user can access are shown. Bilingual via t(); RTL-safe (all
// positioning is viewport-based).
// Launch: first-sign-in prompt, user menu → "Take the tour",
// or busco.tour() in the console.
// ───────────────────────────────────────────────────────────────

const TOUR_SEEN_KEY = "busco-tour-seen";

// Each step: tab = section id it needs (null = always shown),
// sel = element to spotlight ([data-tour="…"]; null = centered card),
// body = one-liner, points = bullet list with the real mechanics.
const TOUR_STEPS = [
  { tab: null, sel: null, title: "Welcome to Busco Ops Centre", body: "A guided tour of how the system actually works — about three minutes.", points: [
    "The tour adapts to your role — you only see what you can access.",
    "Skip anytime; relaunch it from your profile menu.",
  ]},
  { tab: "hub", sel: '[data-tour="workspace"]', title: "Workspaces", body: "View all cities, or scope to KSA or Bahrain.", points: [
    "Every number, chart and table updates to your selection.",
    "The blue strip under the header always shows what you're viewing.",
  ]},
  { tab: "hub", sel: '[data-tour="kpis"]', title: "Today at a glance", body: "Live numbers from today's logged entries.", points: [
    "Offloaded = parcels taken out this morning.",
    "Delivered + today's rate — measured against the 75% target.",
    "Green means on target, red means attention needed.",
  ]},
  { tab: "hub", sel: '[data-tour="report"]', title: "Morning & evening report", body: "The daily report you used to read on WhatsApp — built automatically.", points: [
    "Morning view: what each client offloaded, with courier counts.",
    "Evening view: delivered per client, with each client's rate.",
    "Totals at the bottom — same format as the old text report.",
  ]},
  { tab: "hub", sel: '[data-tour="chart"]', title: "Trends", body: "Offloaded vs delivered over time.", points: [
    "7D and 30D show daily numbers; 90D groups by week; MAX by month.",
    "Use it to spot growth or a slipping delivery rate early.",
  ]},
  { tab: "log", sel: '[data-tour="upload"]', title: "Courier report upload", body: "The client's per-courier report, imported in seconds.", points: [
    "Pick the client and the report date (usually yesterday), then upload the file(s) for that client's format.",
    "Couriers are matched by the ID the client assigned them — set those in Couriers → edit → per-client details.",
    "The numbers feed the courier stats and the Reconcile comparison automatically.",
  ]},
  { tab: "hub", sel: '[data-tour="hub-clients"]', title: "Client performance", body: "Every client's all-time numbers in one table.", points: [
    "Rows highlighted red are below the 75% target.",
    "The sparkline shows each client's six-month trend.",
  ]},
  { tab: "log", sel: '[data-tour="phase"]', title: "Morning / evening logging", body: "One day = two quick entries that link together.", points: [
    "Morning: log how many parcels each client/warehouse sent out.",
    "Evening: log how many came back delivered — it lands on the same entry (same date, client, city, warehouse).",
    "Returns are calculated for you: offloaded − delivered.",
  ]},
  { tab: "log", sel: '[data-tour="log-form"]', title: "The entry form", body: "Pick, type one number, save.", points: [
    "Client → city → warehouse cascade: each choice narrows the next.",
    "In the evening, the form shows what was logged that morning and what the returns will be.",
    "If a day is left without evening numbers, the Overview shows a warning until it's completed.",
  ]},
  { tab: "log", sel: '[data-tour="entries"]', title: "Recent entries", body: "Everything that's been logged or imported.", points: [
    "The badge shows the source: M = logged manually, U = client upload.",
    "Filter by source, client or city; export to Excel/CSV/PDF.",
    "Deleting entries is limited to dispatch level and above.",
  ]},
  { tab: "log", sel: '[data-tour="reconcile"]', title: "Reconcile — catch discrepancies", body: "Puts your manual log next to the client's uploaded report.", points: [
    "Matched = both sources agree. Difference = the numbers disagree — investigate.",
    "\"No client report\" / \"Not in daily log\" = one side is missing.",
    "Each cell reads manual / client, with the gap (Δ) highlighted.",
    "This is how under-counts and billing disputes get caught.",
  ]},
  { tab: "clients", sel: '[data-tour="add-client"]', title: "Adding a client", body: "A client is more than a name — its rates drive your money.", points: [
    "PPD rate and COD rate: what you earn per delivered parcel.",
    "COD fee %: your cut of collected cash.",
    "Payment terms set each invoice's due date.",
  ]},
  { tab: "clients", sel: '[data-tour="clients"]', title: "Client analytics", body: "Performance per account.", points: [
    "Click any row for the full picture: city breakdown, trends, PPD vs COD split and COD value.",
    "The rate bar goes green ≥75%, amber 50–74%, red below 50%.",
  ]},
  { tab: "couriers", sel: '[data-tour="add-courier"]', title: "Adding a courier", body: "Register the team that moves the parcels.", points: [
    "Courier ID, phone, and the clients & zones they serve (multi-select).",
    "Freelancer (per-parcel rate) or salaried — this feeds courier costs in Financial.",
  ]},
  { tab: "couriers", sel: '[data-tour="couriers"]', title: "Courier performance", body: "The directory ranks itself.", points: [
    "Tiers from Elite (≥95%) down to Needs Support (<70%), based on delivery rate.",
    "The 7-day rate shows current form, not just history.",
  ]},
  { tab: "alerts", sel: '[data-tour="alerts"]', title: "Alerts", body: "Who needs attention, automatically.", points: [
    "Critical: couriers under 70%. Warning: 70–74%.",
    "Client alerts fire when an account drops below the 75% target.",
    "Below: the leaderboard and full rankings.",
  ]},
  { tab: "alerts", sel: '[data-tour="notify"]', title: "Notify ops", body: "One click turns today's alerts into a message.", points: [
    "Copies a ready-to-paste WhatsApp summary of every critical courier and client to your clipboard.",
  ]},
  { tab: "users", sel: '[data-tour="users"]', title: "Team & approvals", body: "Control who gets in and what they see.", points: [
    "New sign-ups wait as Pending until approved here.",
    "Roles: Warehouse logs only → Dispatch adds ops & alerts → Manager adds clients & team → Owner sees everything incl. Financial.",
    "\"View as\" previews the app exactly as that person sees it.",
  ]},
  { tab: "financial", sel: '[data-tour="financial"]', title: "Financial (owner only)", body: "The money side, locked behind your 4-digit PIN.", points: [
    "It re-locks every time you leave the tab.",
    "Inside: P&L per client, editable rates, courier costs and cashflow.",
    "Invoices: pick client, city, warehouse and month — the bill is built from your delivery data × that client's rates.",
  ]},
];

function buscoTourSeen() { try { return !!localStorage.getItem(TOUR_SEEN_KEY); } catch { return false; } }
function buscoMarkTourSeen() { try { localStorage.setItem(TOUR_SEEN_KEY, "1"); } catch {} }

// ── The walkthrough overlay ──────────────────────────────────
function TourOverlay({ allowed, page, setPage, onClose }) {
  const steps = TOUR_STEPS.filter((s) => s.tab === null || (allowed || []).includes(s.tab));
  const [idx, setIdx] = useState(0);
  const [rect, setRect] = useState(null);
  const [, force] = useState(0);
  const targetRef = useRef(null);
  const step = steps[idx];

  // Navigate to the step's tab, find + scroll to its element, measure it.
  useEffect(() => {
    if (!step) return;
    let cancelled = false;
    if (step.tab && page !== step.tab) setPage(step.tab);
    let tries = 0;
    const find = () => {
      if (cancelled) return;
      const el = step.sel ? document.querySelector(step.sel) : null;
      if (el) {
        targetRef.current = el;
        el.scrollIntoView({ block: "center", behavior: "auto" });
        setRect(el.getBoundingClientRect());
        setTimeout(() => { if (!cancelled && targetRef.current) setRect(targetRef.current.getBoundingClientRect()); }, 120);
      } else if (step.sel && tries++ < 20) {
        setTimeout(find, 100);
      } else {
        targetRef.current = null;
        setRect(null);
      }
    };
    setRect(null);
    targetRef.current = null;
    setTimeout(find, 60);
    return () => { cancelled = true; };
  }, [idx]); // eslint-disable-line

  // Re-measure on resize/scroll so the spotlight tracks its element.
  useEffect(() => {
    const re = () => { if (targetRef.current) { setRect(targetRef.current.getBoundingClientRect()); } force((x) => x + 1); };
    window.addEventListener("resize", re);
    window.addEventListener("scroll", re, true);
    return () => { window.removeEventListener("resize", re); window.removeEventListener("scroll", re, true); };
  }, []);

  // Escape closes (counts as seen).
  useEffect(() => {
    const esc = (e) => { if (e.key === "Escape") finish(); };
    document.addEventListener("keydown", esc);
    return () => document.removeEventListener("keydown", esc);
  }, []); // eslint-disable-line

  if (!step) return null;

  const finish = () => { buscoMarkTourSeen(); onClose(); };
  const last = idx === steps.length - 1;

  // Card placement: under the element if it fits, otherwise above; centered when no target.
  const vw = window.innerWidth, vh = window.innerHeight;
  const CW = Math.min(360, vw - 24);
  const CH = step.points ? 210 + step.points.length * 34 : 200; // estimate for clamping
  let cardTop, cardLeft;
  if (!rect) {
    cardTop = Math.max(12, vh / 2 - CH / 2);
    cardLeft = vw / 2 - CW / 2;
  } else {
    const below = rect.bottom + 14;
    cardTop = (below + CH < vh - 96) ? below : Math.max(12, rect.top - CH - 14);
    cardLeft = Math.min(Math.max(12, rect.left), vw - CW - 12);
  }
  const pad = 6;

  return (
    <div className="tour-root" dir={document.documentElement.getAttribute("dir") || "ltr"}>
      {rect
        ? <div className="tour-spot" style={{ top: rect.top - pad, left: rect.left - pad, width: rect.width + pad * 2, height: rect.height + pad * 2 }} />
        : <div className="tour-dim" />}
      <div className="tour-card" style={{ top: cardTop, left: cardLeft, width: CW }}>
        <div className="tour-step-n mono">{idx + 1} / {steps.length}</div>
        <div className="tour-title">{window.t(step.title)}</div>
        <div className="tour-body">{window.t(step.body)}</div>
        {step.points &&
          <ul className="tour-points">
            {step.points.map((p, i) => <li key={i}>{window.t(p)}</li>)}
          </ul>
        }
        <div className="tour-actions">
          <button className="btn sm" onClick={finish}>{window.t("Skip tour")}</button>
          <div style={{ display: "flex", gap: 6, marginInlineStart: "auto" }}>
            {idx > 0 && <button className="btn sm" onClick={() => setIdx(idx - 1)}>{window.t("Back")}</button>}
            <button className="btn primary sm" onClick={() => (last ? finish() : setIdx(idx + 1))}>
              {last ? window.t("Finish 🎉") : window.t("Next")}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── First-visit prompt (once per browser) ────────────────────
function TourPrompt({ onStart }) {
  const [hidden, setHidden] = useState(buscoTourSeen());
  if (hidden) return null;
  const dismiss = () => { buscoMarkTourSeen(); setHidden(true); };
  return (
    <div className="tour-prompt">
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <div className="tour-prompt-ic"><Icon name="flag" size={15} color="var(--b700)" /></div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 12.5, fontWeight: 700 }}>{window.t("New here?")}</div>
          <div style={{ fontSize: 11.5, color: "var(--muted)" }}>{window.t("Take a two-minute tour of the system.")}</div>
        </div>
      </div>
      <div style={{ display: "flex", gap: 6, justifyContent: "flex-end", marginTop: 10 }}>
        <button className="btn sm" onClick={dismiss}>{window.t("Maybe later")}</button>
        <button className="btn primary sm" onClick={() => { setHidden(true); onStart(); }}>{window.t("Take the tour")}</button>
      </div>
    </div>
  );
}

Object.assign(window, { TourOverlay, TourPrompt, buscoTourSeen, buscoMarkTourSeen });
