/* ============ CoreApp — the tenant-agnostic core component ============
   The CENTER of every screen. It reads catalog/api/user from the TenantContext and never references
   a brand or window.HARMONY. Chrome (AnnounceBar/StoreHeader/StoreFooter) is the variable per-district
   frame around it. Role/profile/family actions are wired to the live backend; resend is still a local
   review aid until the email worker lands. */
const { useState, useRef, useEffect, useCallback } = React;
let CID = 100;

// Map a backend /family linkedChildren row to the local child shape (numeric ids -> catalog strings).
function mapFamilyChild(row) {
  return {
    id: "s" + row.student_id,
    studentId: row.student_id,
    name: row.name || row.email || ("Student " + row.student_id),
    email: row.email || null,
    status: row.status === "linked" ? "linked" : "pending",
    claimed: !!row.claimed,                              // true once the child has a BigCommerce account
    campusId: row.campus_id != null ? String(row.campus_id) : null,
    teacherId: row.teacher_id != null ? String(row.teacher_id) : null,
    grade: row.grade || null,
    fromServer: true
  };
}

// Review-aid only (Jumper): synthesize children from the live catalog so cards are populated.
function buildDemoChildren(catalog) {
  const names = ["Maya Johnson", "Eli Johnson", "Noah Johnson"];
  const campuses = catalog.campuses || [];
  return names.map((name, i) => {
    const campus = campuses.length ? campuses[i % campuses.length] : null;
    const teacher = campus ? (catalog.teachersForCampus(campus.id)[0] || null) : null;
    const linked = i < 2;
    return {
      id: "demo" + (i + 1),
      name,
      email: name.toLowerCase().split(" ")[0] + ".j@email.com",
      status: linked ? "linked" : "pending",
      campusId: linked && campus ? campus.id : null,
      teacherId: linked && teacher ? teacher.id : null,
      grade: linked ? "3rd Grade" : null
    };
  });
}

function CoreApp() {
  const tenant = useTenant();
  const catalog = useCatalog();
  const api = useApi();
  const user = useUser();
  const onboarding = useOnboarding();
  const launch = useLaunchContext();
  const embedded = tenant.embedded;                          // iframe mode: render core only, no chrome
  const resumeRole = user && user.role ? user.role : null;   // returning session with a persisted role
  const roleRequired = !!(user && onboarding.needsRole);      // ecommerce account exists, but our app has no role yet
  const campusStorageKey = "schoolStore.selectedCampus." + tenant.config.key;
  const firstCampusId = (catalog.campuses[0] && catalog.campuses[0].id) || null;
  const launchCampusId = launch && launch.campusValid ? String(launch.campusId) : null;
  const defaultCampusId = tenant.defaultCampus && tenant.defaultCampus.campus_id ? String(tenant.defaultCampus.campus_id) : null;
  const storedCampusId = roleRequired ? null : localStorage.getItem(campusStorageKey);
  const initialCampusId = launchCampusId || defaultCampusId || storedCampusId || null;
  const hasExplicitLaunchCampus = !!launchCampusId;
  const launchPage = ((launch && launch.page) || "").toLowerCase().replace(/_/g, "-");
  const requestedPage = ({
    "map": "school",
    "school": "school",
    "campus": "school",
    "find-school": "school",
    "manage": "manageStudents",
    "manage-students": "manageStudents",
    "students": "manageStudents",
    "family": "manageStudents",
    "shop": "store",
    "store": "store",
    "checkout": "store",
    "role": "role",
    "setup": "role"
  })[launchPage] || null;
  const launchReturnTarget = launch && launch.returnUrl && launchCampusId ? "school:" + launchCampusId : null;
  const requestedStoreTarget = requestedPage === "store" && initialCampusId ? "school:" + initialCampusId : null;
  const initialShopTarget = requestedStoreTarget || launchReturnTarget;
  const returnAfterSetup = !!(launch && launch.returnUrl);
  const initialEdit = launchCampusId && onboarding.needsProfile ? { target: "me", ret: launch && launch.returnUrl ? "store" : "hub" } : null;
  const [selectedCampusId, setSelectedCampusId] = useState(() => initialCampusId);
  const selectedCampus = catalog.campusById(selectedCampusId) || null;
  const hasSelectedCampus = !!selectedCampus;

  function initialScreen() {
    if (roleRequired) return "role";
    if (!launch) return "school";
    if (requestedPage === "school") return "school";
    if (requestedPage === "manageStudents") {
      if (!user) return "school";
      if (onboarding.needsRole) return "role";
      if (onboarding.needsProfile) return "studentProfile";
      if (resumeRole === "parent") return onboarding.needsFamily ? "school" : "hub";
      return "hub";
    }
    if (!hasExplicitLaunchCampus) return "school";
    if (!hasSelectedCampus) return "school";
    if (requestedPage === "role") return "role";
    if (!user && initialShopTarget) return "store";
    if (onboarding.needsProfile) return "studentProfile";
    if (onboarding.needsRole) return "role";
    if (initialShopTarget) return "store";
    return resumeRole ? "hub" : "role";
  }

  const [screen, setScreen] = useState(initialScreen);
  const [role, setRole] = useState(resumeRole);
  const [me, setMe] = useState({ name: (user && user.email) || "You", campusId: selectedCampusId || null, teacherId: null, grade: null });
  const [children, setChildren] = useState([]);
  const [shopForId, setShopForId] = useState(initialShopTarget);
  const [edit, setEdit] = useState(initialEdit);        // {target:'me'|childId, ret:'hub'|'linkChild'|'store'}
  const [hubAdd, setHubAdd] = useState(false);    // add-child modal from hub
  const [toasts, setToasts] = useState([]);
  const canvasRef = useRef(null);

  const addToast = useCallback((msg, icon = "check") => {
    const id = ++CID;
    setToasts((t) => [...t, { id, msg, icon }]);
    setTimeout(() => setToasts((t) => t.filter((x) => x.id !== id)), 2800);
  }, []);

  function go(s) { setScreen(s); if (canvasRef.current) canvasRef.current.scrollTop = 0; window.scrollTo({ top: 0 }); }

  useEffect(() => {
    if (user && !(role || resumeRole) && screen !== "role") go("role");
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [user && user.id, role, resumeRole, screen]);

  function saveDefaultCampus(campusId) {
    if (!user || !campusId) return;
    api.saveDefaultCampus({ campusId: campusId }).catch(() => {});
  }

  useEffect(() => {
    if (launchCampusId) localStorage.setItem(campusStorageKey, launchCampusId);
    if (launch && launch.campusInvalid) addToast("Campus from the store was not found. Please choose a campus.", "info");
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  function childByStudentId(studentId) {
    return studentId != null
      ? children.find((child) => child.studentId != null && String(child.studentId) === String(studentId))
      : null;
  }

  function chooseCampus(campusId, studentId) {
    const selectedChild = childByStudentId(studentId);
    localStorage.setItem(campusStorageKey, String(campusId));
    setSelectedCampusId(String(campusId));
    saveDefaultCampus(campusId);
    setMe((m) => ({ ...m, campusId: String(campusId), teacherId: null, grade: null }));
    const activeRole = role || resumeRole;
    if (!activeRole) {
      go("role");
      return;
    }
    if (activeRole === "student") {
      const profile = { campusId: String(campusId), teacherId: null, grade: null };
      api.saveStudentProfile(profile).catch((e) => addToast("Saved locally; server error: " + e.message, "info"));
      if (returnAfterSetup) {
        setShopForId("school:" + campusId);
        go("store");
      } else {
        go("hub");
      }
      return;
    }
    if (activeRole === "teacher" || activeRole === "campus_official") {
      setShopForId("school:" + campusId);
      go("store");
      return;
    }
    if (activeRole === "parent" && returnAfterSetup) {
      setShopForId(selectedChild ? selectedChild.id : "school:" + campusId);
      go("store");
      return;
    }
    go("hub");
  }

  // Independent path: guests can shop a campus directly; signed-in users must complete role first.
  function shopCampusDirect(campusId, studentId) {
    const selectedChild = childByStudentId(studentId);
    localStorage.setItem(campusStorageKey, String(campusId));
    setSelectedCampusId(String(campusId));
    saveDefaultCampus(campusId);
    setMe((m) => ({ ...m, campusId: String(campusId) }));
    const activeRole = role || resumeRole;
    if (user && !activeRole) {
      go("role");
      return;
    }
    if (activeRole === "student") {
      api.saveStudentProfile({ campusId: String(campusId), teacherId: null, grade: null })
        .catch((e) => addToast("Saved locally; server error: " + e.message, "info"));
    }
    setShopForId(selectedChild ? selectedChild.id : "school:" + campusId);
    go("store");
  }

  function continueAfterFamily() {
    if (returnAfterSetup) {
      go("school");
      return;
    }
    go("hub");
  }

  function campusProfile() {
    const campusId = selectedCampusId || firstCampusId;
    return { campusId, teacherId: null, grade: null };
  }

  // Pull any server-side linked children into the list (used on entering the parent flow).
  const loadFamily = useCallback(() => {
    return api.getFamily()
      .then((res) => {
        const rows = (res && res.family && res.family.linkedChildren) || [];
        setChildren(rows.map(mapFamilyChild));          // server is authoritative on (re)entry
      })
      .catch(() => { /* no session — keep whatever is in local state */ });
  }, [api]);

  // Resume a returning session: a persisted role drives the initial screen, and the saved student
  // profile / linked children are hydrated from the live backend instead of starting blank.
  useEffect(() => {
    if (!resumeRole) return;
    if (resumeRole === "student") {
      api.getFamily()
        .then((res) => {
          const sp = res && res.family && res.family.studentProfile;
          if (sp) setMe((m) => ({
            ...m,
            campusId: sp.campus_id != null ? String(sp.campus_id) : m.campusId,
            teacherId: sp.teacher_id != null ? String(sp.teacher_id) : m.teacherId,
            grade: sp.grade || m.grade
          }));
        })
        .catch(() => {});
    } else if (resumeRole === "parent") {
      loadFamily();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // ----- child ops -----
  function addChild(data) {
    // Manual entry only (join-by-code removed): a parent-entered child, always with a campus.
    // Persist, then re-pull the family so the list reflects server truth.
    api.addChild({ name: data.name, email: data.email, campusId: data.campusId || selectedCampusId, teacherId: null, grade: null })
      .then(() => { addToast(data.name + " added"); loadFamily(); })
      .catch((e) => addToast("Couldn’t add child — " + (e.message || "error"), "info"));
  }
  function removeChild(id) {
    const child = children.find((c) => c.id === id);
    if (child && child.studentId != null) api.revokeChild(child.studentId).catch(() => {});
    setChildren((cs) => cs.filter((c) => c.id !== id));
    addToast("Child removed", "trash");
  }
  const resend = (id) => addToast("Courtesy email re-sent", "send");

  // ----- role select (live: POST /onboarding/role) -----
  function chooseRole(r) {
    // Staff roles are locked to the district roster (the server enforces it). Gate navigation on the
    // result so a non-roster email can't proceed as a teacher / campus official.
    if (r === "teacher" || r === "campus_official") {
      api.saveRole(r).then(() => {
        setRole(r);
        if (selectedCampusId) {
          setShopForId("school:" + selectedCampusId);
          go("store");
        } else {
          go("school");
        }
        addToast((r === "teacher" ? "Teacher" : "Campus official") + " tools coming soon - browsing the store", "info");
      }).catch((e) => {
        const rosterBlocked = ((e && e.data && e.data.error) === "email_not_on_roster") || ((e && e.message) === "email_not_on_roster");
        addToast(rosterBlocked
          ? "This email isn’t on your district’s staff roster, so you can’t use a staff role."
          : "Couldn’t save role: " + ((e && e.message) || "error"), "info");
      });
      return;
    }
    api.saveRole(r).then(() => {
      setRole(r);
      if (r === "student") {
        if (selectedCampusId) {
          const profile = campusProfile();
          setMe((m) => ({ ...m, ...profile }));
          api.saveStudentProfile(profile).catch((e) => addToast("Saved locally; server error: " + e.message, "info"));
          if (returnAfterSetup) {
            setShopForId("school:" + profile.campusId);
            go("store");
          } else {
            go("hub");
          }
        } else {
          go("school");
        }
      }
      else if (r === "parent") {
        loadFamily();
        go("linkChild");
      }
    }).catch((e) => addToast("Couldn't save role: " + e.message, "info"));
  }

  // ----- profile save (live for the signed-in student: PUT /students/me/profile) -----
  function saveProfile(p) {
    if (!edit) return;
    if (edit.target === "me") {
      setMe((m) => ({ ...m, ...p }));
      if (role === "student") {
        api.saveStudentProfile(p).catch((e) => addToast("Saved locally; server error: " + e.message, "info"));
      }
    } else {
      const child = children.find((c) => c.id === edit.target);
      setChildren((cs) => cs.map((c) => (c.id === edit.target ? { ...c, ...p } : c)));
      if (child && child.studentId != null) {
        api.updateChild(child.studentId, p).then(() => loadFamily()).catch((e) => addToast("Saved locally; server error: " + (e.message || ""), "info"));
      }
    }
    const ret = edit.ret; setEdit(null);
    go(ret);
    addToast("School info saved");
  }
  function profileBack() { setEdit(null); go(role === "parent" ? "linkChild" : "school"); }

  // ----- shop -----
  function startShop(childId) { setShopForId(childId); go("shopFor"); }
  async function shopContinue(target) {
    if (user && !(role || resumeRole)) {
      go("role");
      return;
    }
    setShopForId(target);
    let msg = "Opening the store";
    if (typeof target === "string" && target.indexOf("school:") === 0) {
      const c = catalog.campusById(target.slice(7)); if (c) msg = "Now shopping the " + c.name + " store";
    } else {
      const ch = children.find((c) => c.id === target);
      if (ch) {
        msg = "Now shopping for " + ch.name;
        if (ch.studentId != null) {
          try {
            await api.createCheckoutIntent(ch.studentId);
          } catch (e) {
            addToast("Couldn't open store for " + ch.name + ": " + ((e && e.message) || "checkout intent failed"), "info");
            return;
          }
        }
      }
    }
    go("store");
    addToast(msg);
  }

  const shopForChild = children.find((c) => c.id === shopForId) || null;
  const studentAsChild = { id: "me", name: me.name || "You", campusId: me.campusId || selectedCampusId, teacherId: null };
  let storeTarget = shopForChild;
  if (shopForId === "me") storeTarget = studentAsChild;
  else if (typeof shopForId === "string" && shopForId.indexOf("school:") === 0) storeTarget = { id: shopForId, name: null, campusId: shopForId.slice(7), isSchool: true };
  const childName = edit && edit.target !== "me" ? (children.find((c) => c.id === edit.target) || {}).name : null;

  // header account visible once past the first onboarding step
  const accountEmail = (user && user.email) || "My Account";
  const account = screen === "school" || screen === "role" ? null
    : { name: role === "student" ? me.name : accountEmail, short: role === "student" ? (me.name || "Student") : accountEmail, seed: 2 };

  function headerCart() {
    if (user && !(role || resumeRole)) {
      go("role");
      return;
    }
    if (role === "student") { go("store"); } else { go("shopFor"); }
  }

  // ----- jumper (review aid) -----
  function jump(target) {
    switch (target) {
      case "school": go("school"); break;
      case "role": setRole(null); go("role"); break;
      case "studentProfile": setRole("student"); setMe({ name: (user && user.email) || "You", ...campusProfile() }); setEdit({ target: "me", ret: "hub" }); go("studentProfile"); break;
      case "linkChild": setRole("parent"); setChildren((c) => c.length ? c : buildDemoChildren(catalog).slice(0, 2)); go("linkChild"); break;
      case "hub": setRole("parent"); setChildren((c) => c.length ? c : buildDemoChildren(catalog)); go("hub"); break;
      case "shopFor": setRole("parent"); setChildren((c) => c.length ? c : buildDemoChildren(catalog)); go("shopFor"); break;
      case "store": setRole("parent"); setChildren((c) => { const n = c.length ? c : buildDemoChildren(catalog); setShopForId(n[0] && n[0].id); return n; }); go("store"); break;
      default: break;
    }
  }

  return (
    <div className={"app-root" + (embedded ? " embed" : "")}>
      {!embedded && <AnnounceBar />}
      {!embedded && <StoreHeader account={account} onAccount={() => go("hub")} onFindSchool={() => go("school")} onCart={headerCart} />}

      <div className="canvas" ref={canvasRef}>
        {screen === "school" && <SchoolFrontPage selectedCampusId={selectedCampusId} students={children} onContinue={chooseCampus} onShopCampus={shopCampusDirect} />}

        {screen === "role" && <RolePicker initial={role} onContinue={chooseRole} />}

        {screen === "studentProfile" && (
          <StudentProfile
            value={edit && edit.target !== "me"
              ? { ...(children.find((c) => c.id === edit.target) || {}), campusId: ((children.find((c) => c.id === edit.target) || {}).campusId || selectedCampusId) }
              : { ...me, campusId: me.campusId || selectedCampusId }}
            childName={childName}
            onBack={profileBack}
            onContinue={saveProfile} />
        )}

        {screen === "linkChild" && (
          <LinkChild children={children} onAdd={addChild} onRemove={removeChild} onResend={resend}
            onSetSchool={(id) => { setEdit({ target: id, ret: "linkChild" }); go("studentProfile"); }}
            onBack={() => go("role")} onContinue={continueAfterFamily} selectedCampus={selectedCampus} />
        )}

        {screen === "hub" && (
          <FamilyHub role={role} me={me} children={children}
            onAddChild={() => setHubAdd(true)}
            onSetSchool={(id) => { setEdit({ target: id, ret: "hub" }); go("studentProfile"); }}
            onShop={startShop} onResend={resend}
            onEditMe={() => { setEdit({ target: "me", ret: "hub" }); go("studentProfile"); }}
            onShopMe={() => { setShopForId("me"); go("store"); }} />
        )}

        {screen === "shopFor" && (
          <ShopFor children={children} initial={shopForId}
            onBack={() => go("hub")} onContinue={shopContinue} />
        )}

        {screen === "store" && (
          <StoreLanding
            shoppingFor={storeTarget}
            onChange={() => (role === "student" ? go("hub") : go("shopFor"))}
            onBackHub={() => go("hub")} />
        )}
      </div>

      {!embedded && <StoreFooter />}

      {hubAdd && <AddChildModal selectedCampus={selectedCampus} onClose={() => setHubAdd(false)} onAdd={(c) => { addChild(c); setHubAdd(false); }} />}
      <Toasts items={toasts} />
      {tenant.reviewToolsEnabled && <Jumper screen={screen} onJump={jump} />}
    </div>
  );
}

/* ============ Floating screen jumper (review aid) ============ */
function Jumper({ screen, onJump }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    function h(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }
    document.addEventListener("mousedown", h);
    return () => document.removeEventListener("mousedown", h);
  }, []);
  const items = [
    ["school", "Find school"],
    ["role", "Role picker"],
    ["studentProfile", "Student profile"],
    ["linkChild", "Link a child"],
    ["hub", "My Family / School Info"],
    ["shopFor", "Shop for child"],
    ["store", "Store (destination)"],
  ];
  return (
    <div className="jumper" ref={ref}>
      {open && (
        <div className="jumper-menu">
          <div className="jm-h">Jump to screen</div>
          {items.map(([id, lbl], i) => (
            <button key={id} className={"jm-item" + (screen === id ? " active" : "")} onClick={() => { onJump(id); setOpen(false); }}>
              <span className="jm-num">{i + 1}</span>{lbl}
            </button>
          ))}
        </div>
      )}
      <button className="jumper-btn" onClick={() => setOpen((v) => !v)}>
        <Icon name="grid" size={16} /> Screens
      </button>
    </div>
  );
}

Object.assign(window, { CoreApp, Jumper, mapFamilyChild, buildDemoChildren });
