/* =========================================================================
 *  Python Tutor — /progress (signed-in user's own dashboard)
 *  -----------------------------------------------------------------------
 *  Reads /users/{myUid}/pythonTutor/... directly from Firestore. Per-user
 *  gate in firestore.rules (passesPythonTutorGate + uid == auth.uid) is
 *  the access boundary. Nothing here writes — display only.
 *
 *  Widgets:
 *    1. Identity card (greet by name)
 *    2. Headline stats (current streak / 7-day minutes / lessons completed)
 *    3. Completed lessons grouped by module (m01 → m13)
 *    4. Leitner box distribution (review queue health)
 *    5. 30-day activity strip (per-day minutes bar chart)
 *    6. Last 5 mastery test results
 *
 *  Design: quiet and dashboardy. No clickbait, no celebratory animations.
 *  Reuses .pt-feature and the .ct-* tokens; adds a few .pt-stat / .pt-bar
 *  helpers in styles-python.css.
 * =======================================================================*/

const { useState, useEffect, useMemo } = React;

function PythonTutorProgress({ onNavigate }) {
  const user = window.usePtUser();
  const [data, setData] = useState(null);
  const [err, setErr]   = useState("");
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!user) { setLoading(false); return; }
    let cancelled = false;
    setLoading(true);
    setErr("");
    window.PYTHON_TUTOR_FUNCTIONS.loadMyPythonTutorProgress()
      .then((d) => { if (!cancelled) setData(d); })
      .catch((e) => {
        if (cancelled) return;
        setErr((e && (e.message || e.code)) || String(e));
      })
      .finally(() => { if (!cancelled) setLoading(false); });
    return () => { cancelled = true; };
  }, [user && user.uid]);

  return (
    <div className="pt-page">
      <window.PtNav route="progress" onNavigate={onNavigate} user={user} />
      <main className="pt-main">
        <section className="pt-soon" style={{ paddingTop: 24, paddingBottom: 8 }}>
          <div className="ct-eyebrow">Your progress</div>
          <h1 className="pt-soon-h1" style={{ fontSize: "clamp(28px, 3.6vw, 36px)" }}>
            {user ? `Hi, ${user.name || (user.email || "").split("@")[0]}.` : "Your progress"}
          </h1>
        </section>

        {loading && <ProgressLoading />}
        {!loading && err && <ProgressError err={err} />}
        {!loading && !err && data && <ProgressBody data={data} />}
      </main>
      <window.PtFooter />
    </div>
  );
}

function ProgressLoading() {
  return (
    <section className="pt-grid">
      {[0, 1, 2].map((i) => (
        <div key={i} className="pt-feature" style={{ minHeight: 120, opacity: 0.6 }}>
          <div className="ct-eyebrow pt-feature-eyebrow">Loading…</div>
        </div>
      ))}
    </section>
  );
}

function ProgressError({ err }) {
  return (
    <div className="pt-feature" style={{ borderColor: "var(--ct-danger)", marginTop: 16 }}>
      <div className="pt-feature-eyebrow ct-eyebrow" style={{ color: "var(--ct-danger)" }}>
        Couldn't load progress
      </div>
      <div className="pt-feature-body" style={{ color: "var(--ct-danger)" }}>{err}</div>
    </div>
  );
}

// ---------- Body --------------------------------------------------------
function ProgressBody({ data }) {
  const { profile, lessons, reviews, mastery, daily } = data;
  const stats = useMemo(() => deriveStats({ profile, lessons, reviews, mastery, daily }), [data]);
  return (
    <>
      <HeadlineStats stats={stats} />
      <ModulesPanel lessons={lessons} />
      <ReviewBoxesPanel reviews={reviews} />
      <DailyActivityPanel daily={daily} />
      <MasteryPanel mastery={mastery} />
    </>
  );
}

function HeadlineStats({ stats }) {
  return (
    <section className="pt-stat-row" aria-label="Headline stats">
      <Stat label="Current streak"   value={stats.currentStreak} unit={stats.currentStreak === 1 ? "day" : "days"} />
      <Stat label="Last 7 days"      value={stats.last7Minutes}  unit="min" />
      <Stat label="Lessons complete" value={stats.completedCount}/>
      <Stat label="Total practice"   value={stats.totalMinutes}  unit="min" />
    </section>
  );
}

function Stat({ label, value, unit }) {
  return (
    <div className="pt-stat">
      <div className="pt-stat-num ct-mono">{value}{unit ? <span className="pt-stat-unit"> {unit}</span> : null}</div>
      <div className="pt-stat-label ct-eyebrow">{label}</div>
    </div>
  );
}

function ModulesPanel({ lessons }) {
  const byModule = useMemo(() => groupLessonsByModule(lessons), [lessons]);
  const modules = Object.keys(byModule).sort(moduleSortKey);
  if (modules.length === 0) {
    return (
      <section className="pt-feature" style={{ marginTop: 16 }}>
        <div className="ct-eyebrow pt-feature-eyebrow">Modules</div>
        <div className="pt-feature-body">
          No lessons synced yet. Open the Python Tutor desktop or Android app
          and complete a lesson to see your progress here.
        </div>
      </section>
    );
  }
  return (
    <section className="pt-feature" style={{ marginTop: 16 }}>
      <div className="ct-eyebrow pt-feature-eyebrow">Modules</div>
      <div className="pt-module-list">
        {modules.map((m) => {
          const items = byModule[m];
          const completed = items.filter(x => x.status === "completed").length;
          const inProg    = items.filter(x => x.status === "in_progress").length;
          const total = items.length;
          const pct = total > 0 ? Math.round((completed / total) * 100) : 0;
          return (
            <div key={m} className="pt-module-row">
              <div className="pt-module-id ct-mono">{m.toUpperCase()}</div>
              <div className="pt-module-bar">
                <div className="pt-module-bar-fill" style={{ width: pct + "%" }} />
              </div>
              <div className="pt-module-meta ct-mono ct-dim">
                {completed}/{total}
                {inProg > 0 ? <span> · {inProg} in progress</span> : null}
              </div>
            </div>
          );
        })}
      </div>
    </section>
  );
}

function ReviewBoxesPanel({ reviews }) {
  // Leitner buckets: 1..5+. Empty queue → friendly empty.
  const dist = useMemo(() => {
    const m = new Map();
    for (let i = 1; i <= 5; i++) m.set(i, 0);
    let dueNow = 0;
    const now = Date.now();
    for (const r of reviews || []) {
      const box = Math.max(1, Math.min(5, Number(r.box || 1)));
      m.set(box, (m.get(box) || 0) + 1);
      const due = r.nextDue ? new Date(r.nextDue).getTime() : 0;
      if (due && due <= now) dueNow++;
    }
    return { dist: m, total: (reviews || []).length, dueNow };
  }, [reviews]);

  const max = Math.max(1, ...Array.from(dist.dist.values()));
  return (
    <section className="pt-feature" style={{ marginTop: 16 }}>
      <div className="ct-eyebrow pt-feature-eyebrow">Spaced repetition queue</div>
      <div className="pt-feature-body" style={{ marginBottom: 12 }}>
        {dist.total > 0
          ? <>{dist.total} cards in rotation · <strong>{dist.dueNow}</strong> due now</>
          : "No review cards yet."}
      </div>
      {dist.total > 0 && (
        <div className="pt-leitner">
          {[1, 2, 3, 4, 5].map((b) => {
            const n = dist.dist.get(b) || 0;
            const h = (n / max) * 100;
            return (
              <div key={b} className="pt-leitner-col">
                <div className="pt-leitner-bar" style={{ height: h + "%" }} title={`${n} card(s)`} />
                <div className="pt-leitner-label ct-mono ct-dim">B{b}</div>
                <div className="pt-leitner-count ct-mono">{n}</div>
              </div>
            );
          })}
        </div>
      )}
    </section>
  );
}

function DailyActivityPanel({ daily }) {
  // Last 30 calendar days, oldest → newest.
  const series = useMemo(() => {
    const byDate = new Map();
    for (const d of daily || []) {
      if (d.id) byDate.set(d.id, Number(d.minutes || 0) || 0);
    }
    const out = [];
    const today = new Date();
    for (let i = 29; i >= 0; i--) {
      const day = new Date(today.getTime() - i * 24 * 60 * 60 * 1000);
      const ymd = day.getFullYear() + "-" +
                  String(day.getMonth() + 1).padStart(2, "0") + "-" +
                  String(day.getDate()).padStart(2, "0");
      out.push({ ymd, minutes: byDate.get(ymd) || 0 });
    }
    return out;
  }, [daily]);
  const max = Math.max(1, ...series.map(s => s.minutes));
  const total = series.reduce((s, x) => s + x.minutes, 0);
  return (
    <section className="pt-feature" style={{ marginTop: 16 }}>
      <div className="ct-eyebrow pt-feature-eyebrow">Last 30 days</div>
      <div className="pt-feature-body" style={{ marginBottom: 12 }}>
        {total > 0
          ? <><strong>{total}</strong> minutes across the last 30 days.</>
          : "No practice recorded in the last 30 days."}
      </div>
      <div className="pt-actstrip">
        {series.map((s) => {
          const h = (s.minutes / max) * 100;
          const dim = s.minutes === 0;
          return (
            <div key={s.ymd}
                 className={"pt-actstrip-bar" + (dim ? " is-dim" : "")}
                 style={{ height: Math.max(3, h) + "%" }}
                 title={`${s.ymd} · ${s.minutes} min`} />
          );
        })}
      </div>
    </section>
  );
}

function MasteryPanel({ mastery }) {
  const sorted = useMemo(() => (mastery || [])
    .slice()
    .sort((a, b) => {
      const at = new Date(a.takenAt || a.completedAt || a.createdAt || 0).getTime();
      const bt = new Date(b.takenAt || b.completedAt || b.createdAt || 0).getTime();
      return bt - at;
    })
    .slice(0, 5), [mastery]);
  if (sorted.length === 0) {
    return (
      <section className="pt-feature" style={{ marginTop: 16, marginBottom: 24 }}>
        <div className="ct-eyebrow pt-feature-eyebrow">Mastery tests</div>
        <div className="pt-feature-body">No mastery tests taken yet.</div>
      </section>
    );
  }
  return (
    <section className="pt-feature" style={{ marginTop: 16, marginBottom: 24 }}>
      <div className="ct-eyebrow pt-feature-eyebrow">Recent mastery tests</div>
      <div className="pt-mastery-list">
        {sorted.map((m, i) => {
          const score = Number(m.scorePct || m.score || 0);
          const passed = !!(m.passed === true || score >= 85);
          const when = m.takenAt || m.completedAt || m.createdAt || null;
          return (
            <div key={m.id || i} className="pt-mastery-row">
              <span className="ct-mono pt-mastery-mod">{(m.moduleId || m.lessonId || "—").toString().toUpperCase()}</span>
              <span className={"pt-mastery-score ct-mono" + (passed ? " is-pass" : " is-fail")}>{Math.round(score)}%</span>
              <span className="ct-mono ct-dim pt-mastery-when">{when ? fmtRel(when) : "—"}</span>
            </div>
          );
        })}
      </div>
    </section>
  );
}

// ---------- helpers -----------------------------------------------------
function deriveStats({ profile, lessons, reviews, mastery, daily }) {
  const completedCount = (lessons || []).filter(l => l.status === "completed").length;
  const totalMinutes = (daily || []).reduce((s, d) => s + (Number(d.minutes || 0) || 0), 0);

  // Last-7 minutes
  const last7Cut = Date.now() - 7 * 24 * 60 * 60 * 1000;
  const last7Minutes = (daily || []).reduce((s, d) => {
    const t = d.id ? new Date(d.id + "T00:00:00").getTime() : 0;
    return t >= last7Cut ? s + (Number(d.minutes || 0) || 0) : s;
  }, 0);

  // Streak. Profile may carry a streak field; fall back to deriving from
  // dailyActivity (consecutive days ending today with minutes > 0 OR
  // usedFreeze === true).
  let currentStreak = Number(profile?.currentStreak || profile?.streak || profile?.streakDays || 0) || 0;
  if (!currentStreak && (daily || []).length > 0) {
    const have = new Map();
    for (const d of daily) {
      const m = Number(d.minutes || 0);
      const f = !!d.usedFreeze;
      if (m > 0 || f) have.set(d.id, true);
    }
    const today = new Date();
    for (let i = 0; i < 365; i++) {
      const day = new Date(today.getTime() - i * 24 * 60 * 60 * 1000);
      const ymd = day.getFullYear() + "-" +
                  String(day.getMonth() + 1).padStart(2, "0") + "-" +
                  String(day.getDate()).padStart(2, "0");
      if (have.get(ymd)) currentStreak++;
      else break;
    }
  }
  return { completedCount, totalMinutes, last7Minutes, currentStreak };
}

function groupLessonsByModule(lessons) {
  const out = {};
  for (const l of lessons || []) {
    // Lesson IDs from the desktop look like "m01_intro_to_python__01_hello_world"
    // — module is the leading "m\d+" segment. Anything that doesn't match
    // is bucketed under "other".
    const id = (l.id || "").toString();
    const match = id.match(/^(m\d+)/i);
    const mod = match ? match[1].toLowerCase() : "other";
    (out[mod] = out[mod] || []).push(l);
  }
  return out;
}
function moduleSortKey(a, b) {
  const an = parseInt(a.replace(/^m/, ""), 10);
  const bn = parseInt(b.replace(/^m/, ""), 10);
  if (Number.isFinite(an) && Number.isFinite(bn)) return an - bn;
  return a.localeCompare(b);
}
function fmtRel(iso) {
  const t = new Date(iso).getTime();
  if (!Number.isFinite(t)) return "—";
  const diff = Date.now() - t;
  const min = Math.floor(diff / 60000);
  if (min < 1) return "just now";
  if (min < 60) return `${min}m ago`;
  const h = Math.floor(min / 60);
  if (h < 24) return `${h}h ago`;
  const d = Math.floor(h / 24);
  if (d < 30) return `${d}d ago`;
  const mo = Math.floor(d / 30);
  return `${mo}mo ago`;
}

window.PythonTutorProgress = PythonTutorProgress;
// Exposed so the owner's /admin drill-in can reuse the exact same widgets
// against another user's data (loaded server-side via callable).
window.PtProgressBody = ProgressBody;
