const config = window.THE_FIN_ACADEMY_CONFIG || {};
const demoCourses = window.THE_FIN_DEMO_COURSES || [];
const academyData = window.THE_FIN_ACADEMY_DATA;
const academyRouting = window.THE_FIN_ACADEMY_ROUTING;
const configured = Boolean(config.supabaseUrl && config.supabasePublishableKey);
const inviteOnly = config.inviteOnly !== false;
const localHost = ["localhost", "127.0.0.1", "::1"].includes(window.location.hostname);
const previewAllowed = Boolean(
  config.previewEnabled && localHost
);
const localSearchParams = new URLSearchParams(window.location.search);
const liveRequested = Boolean(previewAllowed && localSearchParams.get("live") === "1");
const previewRequested = Boolean(
  previewAllowed && !liveRequested
);
const LOGIN_REQUEST_COOLDOWN_MS = 60 * 1000;
const LOGIN_REQUESTED_AT_KEY = "the-fin-academy-login-requested-at";
const AUTH_ERROR_KEYS = ["error", "error_code", "error_description"];

const getAuthCallbackError = () => {
  const hashParams = new URLSearchParams(window.location.hash.replace(/^#/, ""));
  const searchParams = new URLSearchParams(window.location.search);
  const params = hashParams.has("error") || hashParams.has("error_code") ? hashParams : searchParams;
  const code = params.get("error_code") || params.get("error");
  if (!code) return null;
  return {
    code,
    description: params.get("error_description") || "",
  };
};

const getAuthCallbackMessage = (error) => {
  if (!error) return "";
  if (["otp_expired", "access_denied"].includes(error.code)) {
    return "Dieser Login-Link ist abgelaufen oder wurde bereits verwendet. Fordere genau einen neuen Link an und öffne nur die neueste E-Mail.";
  }
  return "Die Anmeldung konnte nicht abgeschlossen werden. Fordere bitte einen neuen Login-Link an und öffne ihn nur einmal.";
};

const clearAuthCallbackError = () => {
  const url = new URL(window.location.href);
  AUTH_ERROR_KEYS.forEach((key) => {
    url.searchParams.delete(key);
  });
  if (!url.hash.startsWith("#/")) {
    const hashParams = new URLSearchParams(url.hash.replace(/^#/, ""));
    AUTH_ERROR_KEYS.forEach((key) => hashParams.delete(key));
    url.hash = hashParams.toString() ? `#${hashParams.toString()}` : "";
  }
  window.history.replaceState({}, document.title, `${url.pathname}${url.search}${url.hash}`);
};

const getRemainingLoginCooldown = () => {
  try {
    const requestedAt = Number(localStorage.getItem(LOGIN_REQUESTED_AT_KEY) || 0);
    return Math.max(0, Math.ceil((requestedAt + LOGIN_REQUEST_COOLDOWN_MS - Date.now()) / 1000));
  } catch (_) {
    return 0;
  }
};

const rememberLoginRequest = () => {
  try { localStorage.setItem(LOGIN_REQUESTED_AT_KEY, String(Date.now())); }
  catch (_) { /* The in-memory cooldown still protects the current page. */ }
};

const getAuthRedirectUrl = () => {
  const currentPath = window.location.pathname.endsWith("/")
    ? window.location.pathname
    : `${window.location.pathname}/`;
  const redirectUrl = localHost
    ? `${window.location.origin}${currentPath}`
    : (config.authRedirectUrl || `${window.location.origin}${currentPath}`);
  return academyRouting.withReturnRoute(redirectUrl, academyRouting.getReturnRoute(window.location));
};

const restoreReturnRoute = () => {
  const route = academyRouting.getReturnRoute(window.location);
  if (!route || window.location.hash === route) return;
  const url = new URL(window.location.href);
  url.searchParams.delete("next");
  url.hash = route;
  window.history.replaceState({}, document.title, `${url.pathname}${url.search}${url.hash}`);
};

const initialAuthCallbackError = getAuthCallbackError();
const initialAuthCallbackMessage = getAuthCallbackMessage(initialAuthCallbackError);
const client = configured
  ? window.supabase.createClient(config.supabaseUrl, config.supabasePublishableKey, {
      auth: { persistSession: true, autoRefreshToken: true, detectSessionInUrl: true },
    })
  : null;

const flattenLessons = (course) =>
  (course.modules || [])
    .sort((a, b) => a.order_index - b.order_index)
    .flatMap((module) => (module.lessons || []).sort((a, b) => a.order_index - b.order_index));

const LEGACY_COURSE_METADATA = {
  "ki-verstehen-und-sicher-starten": {
    path: "KI Grundlagen",
    journey_stage: "Verstehen",
    outcome: "Ein persönlicher KI-Startplan mit geprüften Prompts.",
    deliverable: "KI-Startcheck und erster Praxistest",
  },
  "erster-ki-workflow": {
    path: "KI für produktives Arbeiten",
    journey_stage: "Wiederholbar machen",
    outcome: "Ein getesteter KI-Workflow für eine echte Aufgabe.",
    deliverable: "Workflow Canvas und Drei-Fälle-Test",
  },
  "agent-ready-arbeiten": {
    path: "KI-Agenten und Automatisierung",
    journey_stage: "Agenten einsetzen",
    outcome: "Ein kontrolliertes Briefing für einen Agenten-Piloten.",
    deliverable: "Agenten-Briefing und Pilotplan",
  },
};

const normalizeCourses = (courses) =>
  [...courses]
    .sort((a, b) => a.order_index - b.order_index)
    .map((course) => ({
      ...(LEGACY_COURSE_METADATA[course.slug] || {}),
      ...course,
      course_resources: [...(course.course_resources || [])].sort((a, b) => a.order_index - b.order_index),
      modules: [...(course.modules || [])]
        .sort((a, b) => a.order_index - b.order_index)
        .map((module) => ({
          ...module,
          lessons: [...(module.lessons || [])].sort((a, b) => a.order_index - b.order_index),
        })),
    }));

const getDemoProgress = () => {
  try { return JSON.parse(localStorage.getItem("the-fin-academy-demo-progress") || "[]"); }
  catch (_) { return []; }
};

const JOURNEY_STAGES = ["Verstehen", "Anwenden", "Wiederholbar machen", "Sicher delegieren", "Agenten einsetzen"];
const PATH_ORDER = ["KI Grundlagen", "KI für produktives Arbeiten", "KI-Agenten und Automatisierung"];
const getJourneyStep = (course) => Math.max(1, JOURNEY_STAGES.indexOf(course.journey_stage) + 1);

const ThemeButton = () => {
  const [theme, setTheme] = React.useState(document.documentElement.dataset.theme || "light");
  const toggle = () => {
    const next = theme === "dark" ? "light" : "dark";
    document.documentElement.dataset.theme = next;
    localStorage.setItem("the-fin-theme", next);
    setTheme(next);
  };
  return <button type="button" className="theme-toggle" onClick={toggle} aria-label={theme === "dark" ? "Light Mode aktivieren" : "Dark Mode aktivieren"} aria-pressed={theme === "dark"}>
    <span className="theme-toggle-track" aria-hidden="true"><span className="theme-toggle-thumb" /></span>
    <span>{theme === "dark" ? "Light" : "Dark"}</span>
  </button>;
};

const Brand = () => (
  <a className="brand" href="/academy/">
    <span className="brand-logo" aria-hidden="true"><img src="../icon_images/Design_Image_Logo.png" alt="" /></span>
    <strong className="brand-mark">THE&nbsp;·&nbsp;FIN</strong>
    <span className="brand-tag">Academy</span>
  </a>
);

const getLoginRequestErrorMessage = (error) => {
  if (error && (error.status === 429 || ["over_email_send_rate_limit", "over_request_rate_limit"].includes(error.code))) {
    return "Es wurden zu viele Login-Links angefordert. Bitte warte, bis der Versand wieder freigegeben ist, und verwende danach nur die neueste E-Mail.";
  }
  if (error && error.code === "email_address_invalid") {
    return "Diese E-Mail-Adresse ist ungültig. Bitte prüfe die Schreibweise.";
  }
  return inviteOnly
    ? "Für diese E-Mail ist noch kein Academy-Zugang freigeschaltet. Prüfe die Adresse oder wende dich an THE-FIN."
    : ((error && error.message) || "Der Login-Link konnte nicht gesendet werden. Bitte versuche es später erneut.");
};

const Login = ({ onPreview, initialError }) => {
  const [email, setEmail] = React.useState("");
  const [state, setState] = React.useState(initialError ? "error" : "idle");
  const [message, setMessage] = React.useState(initialError || "");
  const [cooldown, setCooldown] = React.useState(getRemainingLoginCooldown());

  React.useEffect(() => {
    const updateCooldown = () => setCooldown(getRemainingLoginCooldown());
    updateCooldown();
    const timer = window.setInterval(updateCooldown, 1000);
    return () => window.clearInterval(timer);
  }, []);

  const submit = async (event) => {
    event.preventDefault();
    if (!client || cooldown > 0) return;
    setState("loading");
    setMessage("");
    try {
      const { error } = await client.auth.signInWithOtp({
        email: email.trim().toLowerCase(),
        options: { emailRedirectTo: getAuthRedirectUrl(), shouldCreateUser: !inviteOnly },
      });
      if (error) {
        setState("error");
        setMessage(getLoginRequestErrorMessage(error));
        return;
      }
      rememberLoginRequest();
      setCooldown(Math.ceil(LOGIN_REQUEST_COOLDOWN_MS / 1000));
      setState("success");
      setMessage("Wenn diese E-Mail für die Academy freigeschaltet ist, ist der Login-Link unterwegs. Öffne nur den neuesten Link und nur einmal. Bitte prüfe auch deinen Spam-Ordner.");
    } catch (_) {
      setState("error");
      setMessage("Die Verbindung zu Supabase ist gerade nicht erreichbar. Bitte prüfe deine Internetverbindung und versuche es später erneut.");
    }
  };

  const buttonLabel = state === "loading"
    ? "Wird gesendet …"
    : (cooldown > 0 ? `Neuen Link in ${cooldown}s` : (state === "success" ? "Neuen Login-Link anfordern" : "Login-Link anfordern"));

  return (
    <main className="login-page">
      <section className="login-story">
        <div className="login-copy">
          <div className="eyebrow hero-eyebrow">THE-FIN Academy</div>
          <h1 className="display">KI lernen.<br />Direkt anwenden.</h1>
          <p>Kompakte Kurse, klare Vorlagen und praktische Beispiele für den Arbeitsalltag.</p>
          <a className="academy-login-link" href="#academy-login">Zur Anmeldung <span aria-hidden="true">↗</span></a>
        </div>
        <div className="promise-list">
          <div className="promise"><b>Kompakt</b><span>Kurze Lektionen statt stundenlanger Theorie.</span></div>
          <div className="promise"><b>Praktisch</b><span>Guides, Prompts und nachvollziehbare Beispiele.</span></div>
          <div className="promise"><b>Aufbauend</b><span>Vom sicheren Einstieg bis zum eigenen Agenten.</span></div>
        </div>
      </section>
      <section className="login-panel" id="academy-login">
        <div className="login-card">
          <div className="login-brand"><Brand /></div>
          <div className="eyebrow">Zugang nur mit Einladung</div>
          <h2>Willkommen zurück</h2>
          <p>Die Academy ist aktuell für eingeladene Testnutzer geöffnet. Mit deiner freigeschalteten E-Mail erhältst du einen sicheren Login-Link.</p>
          <form onSubmit={submit}>
            <div className="field">
              <label htmlFor="email">E-Mail-Adresse</label>
              <input id="email" type="email" autoComplete="email" required value={email} onChange={(e) => setEmail(e.target.value)} placeholder="name@unternehmen.at" disabled={!configured} />
            </div>
            <button className="btn btn-primary" disabled={!configured || state === "loading" || cooldown > 0}>{buttonLabel}</button>
            {!configured && <p className="form-note">Der echte Login wird nach der Supabase-Konfiguration aktiviert.</p>}
            {configured && inviteOnly && <p className="form-note">Noch keine Einladung? Academy-Zugänge werden derzeit persönlich vergeben.</p>}
            {message && <p className={state === "error" ? "form-error" : "form-success"} role="status" aria-live="polite">{message}</p>}
          </form>
          {previewAllowed && (
            <div className="preview-entry">
              <button className="btn" onClick={onPreview}>Kursbereich als Vorschau öffnen</button>
              <p className="form-note">Vorschaudaten und Fortschritt bleiben nur in diesem Browser.</p>
            </div>
          )}
        </div>
      </section>
    </main>
  );
};

const Header = ({ preview, email, onLogout, onPreview }) => (
  <>
    {preview && <div className="preview-banner">Lokaler Vorschaumodus · keine echten Benutzer- oder Kursdaten</div>}
    <header className="topbar">
      <div className="topbar-inner">
        <Brand />
        <div className="top-actions">
          {email && <span className="user-email">{email}</span>}
          {!preview && previewAllowed && <button className="btn btn-small" onClick={onPreview}>Lokale Vorschau</button>}
          <ThemeButton />
          <button className="btn btn-small" onClick={onLogout}>{preview ? "Vorschau beenden" : "Abmelden"}</button>
        </div>
      </div>
    </header>
  </>
);

const CourseCard = ({ course, progress, onOpen }) => {
  const lessons = flattenLessons(course);
  const done = lessons.filter((lesson) => progress.includes(lesson.id)).length;
  const percent = lessons.length ? Math.round((done / lessons.length) * 100) : 0;
  const completed = lessons.length > 0 && done === lessons.length;
  return (
    <article className="course-card" data-accent={course.accent || "clay"}>
      {course.cover_image && (
        <div className="course-cover">
          <img src={course.cover_image} alt={course.cover_alt || ""} loading="lazy" />
        </div>
      )}
      {course.path && <div className="course-path"><span>Schritt {getJourneyStep(course)} von {JOURNEY_STAGES.length}</span>{course.journey_stage && <strong>{course.journey_stage}</strong>}</div>}
      <div className="eyebrow">{course.eyebrow || course.level}</div>
      <h2>{course.title}</h2>
      <p>{course.summary}</p>
      {course.outcome && <div className="course-outcome"><span>Dein Ergebnis</span><strong>{course.outcome}</strong></div>}
      <div className="course-meta"><span>{course.level}</span><span>{course.duration_minutes} Min.</span></div>
      <div className="course-card-footer">
        {course.coming_soon ? (
          <button className="btn" disabled>In Vorbereitung</button>
        ) : (
          <>
            <div className="progress-track" role="progressbar" aria-label={`Fortschritt in ${course.title}`} aria-valuemin="0" aria-valuemax="100" aria-valuenow={percent}><div className="progress-bar" style={{ width: `${percent}%` }} /></div>
            <div className="progress-label"><span>{done} von {lessons.length} Lektionen</span><span>{percent}%</span></div>
            <button className="btn btn-primary" onClick={() => onOpen(course)}>{completed ? "Kurs wiederholen" : done ? "Weiterlernen" : "Kurs starten"}</button>
          </>
        )}
      </div>
    </article>
  );
};

const AcademyJourney = () => (
  <div className="academy-journey" aria-hidden="true">
    <svg viewBox="0 0 360 320" fill="none">
      <g stroke="var(--rule-2)" strokeWidth="1">
        <circle cx="185" cy="150" r="118" />
        <ellipse cx="185" cy="150" rx="58" ry="118" transform="rotate(28 185 150)" />
        <ellipse cx="185" cy="150" rx="118" ry="44" transform="rotate(28 185 150)" />
        <path d="M79 99L290 202M103 64L309 166" />
      </g>
      <path className="academy-journey-route" d="M30 282C42 213 88 225 153 239S293 221 277 165S215 139 231 166S308 150 308 48" stroke="var(--accent)" strokeWidth="1.8" pathLength="1" />
      <path d="M308 37L294 73L309 63L327 68Z" fill="var(--bg)" stroke="var(--ink)" strokeWidth="1.5" strokeLinejoin="round" />
      <circle cx="30" cy="282" r="4" fill="var(--bg)" stroke="var(--accent)" strokeWidth="1.5" />
      <circle cx="153" cy="239" r="3" fill="var(--accent)" />
    </svg>
    <span>IT’S GOING TO BE A JOURNEY.</span>
  </div>
);

const Dashboard = ({ courses, progress, onOpen }) => {
  const [activePath, setActivePath] = React.useState("Alle");
  const availablePaths = [
    ...PATH_ORDER.filter((path) => courses.some((course) => course.path === path)),
    ...new Set(courses.map((course) => course.path || "Weitere Kurse").filter((path) => !PATH_ORDER.includes(path))),
  ];
  const visibleCourses = activePath === "Alle"
    ? courses
    : courses.filter((course) => (course.path || "Weitere Kurse") === activePath);
  return <>
    <section className="dashboard-hero wrap">
      <div className="academy-section-label"><span>01 — DIE LERNREISE</span><span>THE FUTURE IS NOW.</span></div>
      <div className="academy-hero-stage">
        <h1 className="display">KI verstehen.<br />Wissen anwenden.</h1>
        <AcademyJourney />
      </div>
      <div className="academy-hero-bottom">
        <p className="lede">Vom ersten Verständnis zur praktischen Anwendung. Schritt für Schritt, im eigenen Tempo und an konkreten Aufgaben.</p>
        <a className="btn" href="#kurskatalog">Kurse entdecken <span aria-hidden="true">↗</span></a>
      </div>
      <div className="journey-rail" aria-label="Lernreise">
        {JOURNEY_STAGES.map((stage, index) => <div className="journey-stage" key={stage}><span>{index + 1}</span><strong>{stage}</strong></div>)}
      </div>
    </section>
    <section className="catalog wrap" id="kurskatalog">
      <div className="academy-section-label"><span>02 — DIE KURSE</span><span>VERSTEHEN · ANWENDEN · VERTIEFEN</span></div>
      {courses.length > 0 && <div className="path-filter" aria-label="Kurse nach Lernpfad filtern">
        {["Alle", ...availablePaths].map((path) => <button className={activePath === path ? "active" : ""} onClick={() => setActivePath(path)} key={path}>{path}</button>)}
      </div>}
      <div className="course-grid">{visibleCourses.map((course) => <CourseCard key={course.id} course={course} progress={progress} onOpen={onOpen} />)}</div>
      {!courses.length && <div className="empty-state"><h2>Noch keine Kurse verfügbar</h2><p>Bitte lade die Seite neu. Falls das Problem bleibt, prüfen wir die Academy-Verbindung.</p></div>}
    </section>
  </>;
};

const ContentBlock = ({ block, onEvent }) => {
  const [copied, setCopied] = React.useState(false);
  const [quizChoice, setQuizChoice] = React.useState(null);
  if (block.type === "lead") return <div className="content-block lead-block"><p>{block.text}</p></div>;
  if (block.type === "image") return <figure className="content-block lesson-image"><img src={block.src} alt={block.alt || ""} loading="lazy" />{block.caption && <figcaption>{block.caption}</figcaption>}</figure>;
  if (block.type === "text") return <div className="content-block"><h2>{block.title}</h2><p>{block.text}</p></div>;
  if (block.type === "callout") return <aside className="content-block callout"><h2>{block.title}</h2><p>{block.text}</p></aside>;
  if (block.type === "visual") return <div className="content-block"><h2>{block.title}</h2><div className="visual-flow">{block.items.map((item, i) => <div className="visual-step" key={item}><span>0{i + 1}</span><span>{item}</span></div>)}</div></div>;
  if (block.type === "steps") return <div className="content-block"><h2>{block.title}</h2><div className="step-list">{block.items.map((item, i) => <div className="step-item" key={item.title}><div className="step-number">{i + 1}</div><div><b>{item.title}</b><p>{item.text}</p></div></div>)}</div></div>;
  if (block.type === "checklist") return <div className="content-block"><h2>{block.title}</h2><ul className="checklist">{block.items.map((item) => <li key={item}>{item}</li>)}</ul></div>;
  if (block.type === "prompt") {
    const copy = async () => { await navigator.clipboard.writeText(block.text); setCopied(true); window.setTimeout(() => setCopied(false), 1600); };
    return <div className="content-block"><h2>{block.title}</h2><div className="prompt-box"><button className="copy-btn" onClick={copy}>{copied ? "Kopiert" : "Kopieren"}</button><pre>{block.text}</pre></div></div>;
  }
  if (block.type === "exercise") return <div className="content-block exercise-block"><div className="eyebrow">Praxisauftrag</div><h2>{block.title}</h2><p>{block.text}</p>{block.deliverable && <div className="exercise-deliverable"><span>Ergebnis</span><strong>{block.deliverable}</strong></div>}{block.items && <ul className="checklist">{block.items.map((item) => <li key={item}>{item}</li>)}</ul>}</div>;
  if (block.type === "transfer") return <div className="content-block exercise-block transfer-block"><div className="eyebrow">Mini-Transfer</div><h2>{block.title}</h2><p>{block.text}</p>{block.deliverable && <div className="exercise-deliverable"><span>Arbeitsnotiz</span><strong>{block.deliverable}</strong></div>}{block.items && <ul className="checklist">{block.items.map((item) => <li key={item}>{item}</li>)}</ul>}</div>;
  if (block.type === "example") return <section className="content-block example-block"><div className="eyebrow">Musterlösung</div><h2>{block.title}</h2><div className="example-grid"><div><span>Beispielinput</span><p>{block.input}</p></div><div><span>Beispieloutput</span><p>{block.output}</p></div></div><p className="example-review"><strong>Qualitätsblick:</strong> {block.review}</p></section>;
  if (block.type === "handoff") return <aside className="content-block handoff-block"><div className="eyebrow">Kursübergang</div><h2>{block.title}</h2><p>{block.text}</p></aside>;
  if (block.type === "comparison") return <div className="content-block"><h2>{block.title}</h2><div className="comparison-grid">{block.items.map((item) => <section key={item.title}><div className="eyebrow">{item.label}</div><h3>{item.title}</h3><p>{item.text}</p></section>)}</div></div>;
  if (block.type === "quiz") {
    const answered = quizChoice !== null;
    return <div className="content-block quiz-block"><div className="eyebrow">Wissenscheck</div><h2>{block.question}</h2><div className="quiz-options">{block.options.map((option, index) => <button className={`quiz-option ${answered && index === block.answer ? "correct" : ""} ${answered && index === quizChoice && index !== block.answer ? "wrong" : ""}`} disabled={answered} onClick={() => { setQuizChoice(index); onEvent && onEvent("quiz_answered", { correct: index === block.answer, question: block.question }); }} key={option}>{option}</button>)}</div>{answered && <p className="quiz-explanation"><strong>{quizChoice === block.answer ? "Richtig." : "Noch nicht ganz."}</strong> {block.explanation}</p>}</div>;
  }
  return null;
};

const LessonFeedback = ({ lesson, onSubmit }) => {
  const [rating, setRating] = React.useState(null);
  const [question, setQuestion] = React.useState("");
  const [saved, setSaved] = React.useState(false);
  const submit = async (event) => {
    event.preventDefault();
    if (!rating && !question.trim()) return;
    await onSubmit({ rating, question: question.trim() });
    setSaved(true);
  };
  return <section className="lesson-feedback">
    <div><div className="eyebrow">Hilf uns beim Verbessern</div><h2>War diese Lektion hilfreich?</h2></div>
    {saved ? <p className="form-success">Danke. Dein Hinweis ist gespeichert.</p> : <form onSubmit={submit}>
      <div className="rating-row">{[[3, "Ja"], [2, "Teilweise"], [1, "Nein"]].map(([value, label]) => <button type="button" className={`btn btn-small ${rating === value ? "selected" : ""}`} onClick={() => setRating(value)} key={value}>{label}</button>)}</div>
      <label htmlFor={`question-${lesson.id}`}>Was war unklar oder welche Frage ist offen?</label>
      <textarea id={`question-${lesson.id}`} value={question} maxLength="2000" onChange={(event) => setQuestion(event.target.value)} placeholder="Optionaler Hinweis – bitte ohne persönliche oder vertrauliche Daten" rows="3" />
      <button className="btn btn-small" disabled={!rating && !question.trim()}>Feedback speichern</button>
    </form>}
  </section>;
};

const CourseView = ({ course, lesson, progress, progressSaving, onSelectLesson, onBack, onComplete, onDownloadResource, onFeedback, onEvent }) => {
  const lessons = flattenLessons(course);
  const currentIndex = lessons.findIndex((item) => item.id === lesson.id);
  const next = lessons[currentIndex + 1];
  const isDone = progress.includes(lesson.id);
  return (
    <div className="course-layout">
      <aside className="course-sidebar">
        <button className="back-link" onClick={onBack}>← Alle Kurse</button>
        {course.cover_image && <img className="sidebar-cover" src={course.cover_image} alt="" />}
        <h1>{course.title}</h1>
        <p>{course.description}</p>
        {course.deliverable && <div className="sidebar-result"><span>Dein Kursprojekt</span><strong>{course.deliverable}</strong></div>}
        <div className="progress-track" role="progressbar" aria-label="Kursfortschritt" aria-valuemin="0" aria-valuemax="100" aria-valuenow={Math.round((lessons.filter((item) => progress.includes(item.id)).length / lessons.length) * 100)}><div className="progress-bar" style={{ width: `${Math.round((lessons.filter((item) => progress.includes(item.id)).length / lessons.length) * 100)}%` }} /></div>
        {(course.course_resources || []).length > 0 && (
          <div className="course-resources">
            <div className="module-title">Materialien</div>
            {course.course_resources.map((resource) => (
              <div className="resource-card" key={resource.id || resource.storage_path}>
                <div>
                  <strong>{resource.title}</strong>
                  <p>{resource.description}</p>
                </div>
                <button className="btn btn-small" onClick={() => onDownloadResource(resource)}>PDF herunterladen</button>
              </div>
            ))}
          </div>
        )}
        {course.modules.map((module) => (
          <div className="module" key={module.id}>
            <div className="module-title">{module.title}</div>
            {module.lessons.map((item) => (
              <button className={`lesson-link ${item.id === lesson.id ? "active" : ""}`} onClick={() => onSelectLesson(item)} key={item.id}>
                <span className={`lesson-status ${progress.includes(item.id) ? "done" : ""}`}>{progress.includes(item.id) ? "✓" : ""}</span>
                <span>{item.title}</span>
                <span className="lesson-minutes">{item.duration_minutes}m</span>
              </button>
            ))}
          </div>
        ))}
      </aside>
      <article className="lesson">
        <section className="mobile-course-tools" aria-label="Kursnavigation">
          <label htmlFor="mobile-lesson-select">Lektion auswählen</label>
          <select id="mobile-lesson-select" value={lesson.id} onChange={(event) => onSelectLesson(lessons.find((item) => item.id === event.target.value))}>
            {course.modules.map((module) => (
              <optgroup label={module.title} key={module.id}>
                {module.lessons.map((item) => <option value={item.id} key={item.id}>{progress.includes(item.id) ? "✓ " : ""}{item.title} · {item.duration_minutes} Min.</option>)}
              </optgroup>
            ))}
          </select>
          {(course.course_resources || []).map((resource) => <button className="btn btn-small" onClick={() => onDownloadResource(resource)} key={resource.id || resource.storage_path}>{resource.title} herunterladen</button>)}
        </section>
        <header className="lesson-head">
          <div className="eyebrow">Lektion {currentIndex + 1} von {lessons.length} · {lesson.duration_minutes} Minuten</div>
          <h1>{lesson.title}</h1>
          <p>{lesson.summary}</p>
        </header>
        <div className="lesson-content">{(lesson.content || []).map((block, i) => <ContentBlock block={block} onEvent={onEvent} key={`${lesson.id}-${block.type}-${i}`} />)}</div>
        <LessonFeedback lesson={lesson} onSubmit={(feedback) => onFeedback(lesson.id, feedback)} key={lesson.id} />
        <footer className="lesson-footer">
          <button className="btn" disabled={progressSaving} aria-busy={progressSaving} onClick={() => onComplete(lesson.id)}>{progressSaving ? "Wird gespeichert …" : (isDone ? "Als offen markieren" : "Lektion abschließen")}</button>
          {next && <button className="btn btn-primary" onClick={() => onSelectLesson(next)}>Nächste Lektion →</button>}
        </footer>
      </article>
    </div>
  );
};

const Academy = ({ preview, session, onExit, onPreview }) => {
  const [courses, setCourses] = React.useState(preview ? normalizeCourses(demoCourses) : []);
  const [progress, setProgress] = React.useState(preview ? getDemoProgress() : []);
  const [loading, setLoading] = React.useState(!preview);
  const [loadError, setLoadError] = React.useState("");
  const [loadAttempt, setLoadAttempt] = React.useState(0);
  const [progressError, setProgressError] = React.useState("");
  const [savingLessonId, setSavingLessonId] = React.useState(null);
  const progressSavingRef = React.useRef(false);
  const [selection, setSelection] = React.useState(null);
  const [routeMessage, setRouteMessage] = React.useState("");

  React.useEffect(() => {
    if (preview || !client) return;
    let active = true;
    const load = async () => {
      setLoading(true);
      setLoadError("");
      try {
        const { courseData, progressData } = await academyData.loadAcademyData(client, session.user.id);
        if (!active) return;
        setCourses(normalizeCourses(courseData));
        setProgress(progressData.map((item) => item.lesson_id));
      } catch (error) {
        console.error(error);
        if (!active) return;
        setCourses([]);
        setProgress([]);
        setSelection(null);
        setLoadError("Die Kursdaten konnten gerade nicht vollständig geladen werden.");
      } finally {
        if (active) setLoading(false);
      }
    };
    load();
    return () => { active = false; };
  }, [preview, session, loadAttempt]);

  const trackEvent = async (eventType, { courseId, lessonId, metadata = {} } = {}) => {
    if (preview || !session || !client) return;
    const { error } = await client.from("learning_events").insert({
      user_id: session.user.id,
      course_id: courseId || selection?.course?.id || null,
      lesson_id: lessonId || selection?.lesson?.id || null,
      event_type: eventType,
      metadata,
    });
    if (error) console.error(error);
  };
  const selectLesson = (course, lesson, { openedCourse = false } = {}) => {
    if (!course || !lesson) return;
    const route = academyRouting.lessonRoute(course, lesson);
    if (window.location.hash !== route) {
      window.history.pushState({}, document.title, `${window.location.pathname}${window.location.search}${route}`);
    }
    setRouteMessage("");
    setSelection({ course, lesson });
    window.scrollTo(0, 0);
    if (openedCourse) trackEvent("course_opened", { courseId: course.id, lessonId: lesson.id });
    trackEvent("lesson_viewed", { courseId: course.id, lessonId: lesson.id });
  };
  const openCourse = (course) => {
    const lessons = flattenLessons(course);
    const firstOpen = lessons.find((lesson) => !progress.includes(lesson.id)) || lessons[0];
    if (firstOpen) selectLesson(course, firstOpen, { openedCourse: true });
  };
  const showCourseOverview = () => {
    if (window.location.hash) {
      window.history.pushState({}, document.title, `${window.location.pathname}${window.location.search}`);
    }
    setRouteMessage("");
    setSelection(null);
    window.scrollTo(0, 0);
  };
  React.useEffect(() => {
    if (loading) return undefined;
    const syncSelectionFromRoute = () => {
      const result = academyRouting.resolveRoute(courses, academyRouting.parseRoute(window.location.hash));
      setSelection(result.selection);
      setRouteMessage(result.message);
    };
    syncSelectionFromRoute();
    window.addEventListener("hashchange", syncSelectionFromRoute);
    window.addEventListener("popstate", syncSelectionFromRoute);
    return () => {
      window.removeEventListener("hashchange", syncSelectionFromRoute);
      window.removeEventListener("popstate", syncSelectionFromRoute);
    };
  }, [courses, loading]);
  const toggleComplete = async (lessonId) => {
    if (progressSavingRef.current) return;
    const isDone = progress.includes(lessonId);
    const next = isDone ? progress.filter((id) => id !== lessonId) : [...progress, lessonId];
    if (preview) {
      setProgress(next);
      localStorage.setItem("the-fin-academy-demo-progress", JSON.stringify(next));
      return;
    }
    progressSavingRef.current = true;
    setSavingLessonId(lessonId);
    setProgressError("");
    try {
      await academyData.persistLessonProgress(client, {
        userId: session.user.id,
        lessonId,
        isDone,
        completedAt: new Date().toISOString(),
      });
      setProgress(next);
      trackEvent(isDone ? "lesson_reopened" : "lesson_completed", { lessonId });
      if (!isDone && selection?.course) {
        const courseLessons = flattenLessons(selection.course);
        const courseCompleted = courseLessons.length > 0 && courseLessons.every((lesson) => next.includes(lesson.id));
        if (courseCompleted) trackEvent("course_completed", { courseId: selection.course.id, lessonId });
      }
    } catch (error) {
      console.error(error);
      setProgressError("Der Fortschritt konnte nicht gespeichert werden. Bitte versuche es erneut.");
    } finally {
      progressSavingRef.current = false;
      setSavingLessonId(null);
    }
  };
  const downloadResource = async (resource) => {
    let href = resource.local_path;
    if (!preview) {
      const { data, error } = await client.storage
        .from("academy-resources")
        .createSignedUrl(resource.storage_path, 60, { download: true });
      if (error) {
        console.error(error);
        window.alert("Das Arbeitsblatt konnte gerade nicht geladen werden. Bitte versuche es erneut.");
        return;
      }
      href = data.signedUrl;
    }
    const link = document.createElement("a");
    link.href = href;
    link.download = resource.filename || "THE-FIN-Arbeitsblatt.pdf";
    link.rel = "noopener";
    document.body.appendChild(link);
    link.click();
    link.remove();
    trackEvent("resource_downloaded", { metadata: { storage_path: resource.storage_path } });
  };
  const saveFeedback = async (lessonId, feedback) => {
    if (preview) {
      const entries = JSON.parse(localStorage.getItem("the-fin-academy-demo-feedback") || "[]");
      localStorage.setItem("the-fin-academy-demo-feedback", JSON.stringify([...entries, { lessonId, ...feedback, createdAt: new Date().toISOString() }]));
      return;
    }
    const { error } = await client.from("lesson_feedback").upsert({ user_id: session.user.id, lesson_id: lessonId, rating: feedback.rating, question: feedback.question || null, updated_at: new Date().toISOString() }, { onConflict: "user_id,lesson_id" });
    if (error) throw error;
    trackEvent("feedback_submitted", { lessonId, metadata: { rating: feedback.rating, has_question: Boolean(feedback.question) } });
  };
  if (loading) return <div className="loading">Academy wird geladen …</div>;
  return (
    <div className="academy-shell">
      <Header preview={preview} email={session && session.user.email} onLogout={onExit} onPreview={onPreview} />
      {loadError ? <div className="academy-alert wrap" role="alert"><p>{loadError}</p><button className="btn btn-small" type="button" onClick={() => setLoadAttempt((attempt) => attempt + 1)}>Erneut versuchen</button></div> : <>
        {progressError && <div className="academy-alert wrap" role="alert"><p>{progressError}</p></div>}
        {routeMessage && <div className="academy-alert wrap" role="alert"><p>{routeMessage}</p></div>}
        {selection ? <CourseView course={selection.course} lesson={selection.lesson} progress={progress} progressSaving={savingLessonId === selection.lesson.id} onBack={showCourseOverview} onSelectLesson={(lesson) => selectLesson(selection.course, lesson)} onComplete={toggleComplete} onDownloadResource={downloadResource} onFeedback={saveFeedback} onEvent={(eventType, metadata) => trackEvent(eventType, { metadata })} /> : <Dashboard courses={courses} progress={progress} onOpen={openCourse} />}
      </>}
    </div>
  );
};

const App = () => {
  const [session, setSession] = React.useState(null);
  const [preview, setPreview] = React.useState(previewRequested);
  const [ready, setReady] = React.useState(previewRequested || !configured);
  const [authError, setAuthError] = React.useState(initialAuthCallbackMessage);
  React.useEffect(() => {
    if (!client) return;
    if (initialAuthCallbackError) clearAuthCallbackError();
    client.auth.getSession()
      .then(({ data, error }) => {
        if (data.session) restoreReturnRoute();
        setSession(data.session);
        if (error && !initialAuthCallbackMessage) {
          setAuthError("Die Anmeldung konnte nicht geprüft werden. Bitte lade die Seite neu oder fordere einen neuen Login-Link an.");
        }
        setReady(true);
      })
      .catch(() => {
        setAuthError("Die Academy-Verbindung konnte nicht geprüft werden. Bitte lade die Seite später erneut.");
        setReady(true);
      });
    const { data } = client.auth.onAuthStateChange((_event, nextSession) => {
      if (nextSession) restoreReturnRoute();
      setSession(nextSession);
      if (nextSession) setAuthError("");
    });
    return () => data.subscription.unsubscribe();
  }, []);
  const exit = async () => {
    if (preview) { setPreview(false); return; }
    if (client) await client.auth.signOut({ scope: "local" });
  };
  if (!ready) return <div className="loading">Login wird geprüft …</div>;
  if (!session && !preview) return <Login initialError={authError} onPreview={() => setPreview(true)} />;
  return <Academy preview={preview} session={session} onExit={exit} onPreview={() => setPreview(true)} key={preview ? "preview" : "live"} />;
};

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