// instructor-dashboard.jsx — Teacher's weekly schedule + availability + balance.
// Wired to Supabase via window.useDashboardData() + window.useAuth().
//
// DAY-OF-WEEK CONVENTION (important):
//   UI grid uses 0=Mon, 6=Sun (matches the design canvas).
//   DB stores 0=Sun, 6=Sat. Conversion helpers below: mockDay <-> realDay.
//
// HOURS displayed in the calendar grid are now DYNAMIC: union of every hour
// where the teacher has availability or an existing booking, padded by 1
// hour on each side. Falls back to 8a–8p if there's nothing yet. This way
// teachers who work nights see those hours and teachers who work days don't
// scroll through 24 empty rows.

const INST_DAYS   = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'];
const INST_MONTHS = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];

const instH     = h => h === 0 ? '12 AM' : h === 12 ? '12 PM' : h > 12 ? (h-12)+' PM' : h+' AM';
// Whole dollars show no decimals ($60); fractional amounts show cents ($207.50,
// $45.25), matching the admin Payouts tab so the same balance reads identically
// on both sides. Round to cents first so float dust doesn't render as "$207.00".
const instFmt$  = v => {
  const n = Math.round((Number(v) || 0) * 100) / 100;
  return '$' + (Number.isInteger(n) ? n.toLocaleString() : n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }));
};
// Default hour selector for the AddLessonModal dropdown — always full 0..23.
const INST_HOURS_FULL = Array.from({ length: 24 }, (_, h) => h);
// Compute the visible hour range for the calendar grid.
const computeVisibleHours = (availMap, bookings) => {
  const hours = new Set();
  for (let i = 0; i < 7; i++) for (const h of (availMap?.[i] || [])) hours.add(h);
  for (const b of (bookings || [])) {
    if (b.status === 'cancelled') continue;
    const d = new Date(b.scheduledAt);
    hours.add(d.getHours());
  }
  if (hours.size === 0) return [8,9,10,11,12,13,14,15,16,17,18,19,20];
  let lo = Math.min(...hours), hi = Math.max(...hours);
  lo = Math.max(0,  lo - 1);
  hi = Math.min(23, hi + 1);
  const out = [];
  for (let h = lo; h <= hi; h++) out.push(h);
  return out;
};

// Local date helpers (no UTC drift)
const localDateStr = (d) => `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
const niceDateStr  = (d) => d.toLocaleDateString(undefined, { weekday:'short', month:'short', day:'numeric' });
const sameLocalDay = (a, b) => a.getFullYear()===b.getFullYear() && a.getMonth()===b.getMonth() && a.getDate()===b.getDate();

// Real today
const INST_TODAY = (() => { const d = new Date(); d.setHours(0,0,0,0); return d; })();

const instWeekDates = (offset) => {
  const dow = INST_TODAY.getDay();
  const mon = new Date(INST_TODAY);
  mon.setDate(INST_TODAY.getDate() - (dow === 0 ? 6 : dow - 1) + offset * 7);
  mon.setHours(0,0,0,0);
  return Array.from({length:7}, (_,i) => { const d = new Date(mon); d.setDate(mon.getDate()+i); return d; });
};

// Day-of-week conversions (UI uses Mon=0, DB uses Sun=0)
const mockDayToRealDay = (m) => (m + 1) % 7;
const realDayToMockDay = (r) => (r + 6) % 7;

// Expand DASHBOARD_DATA.teacherAvailability (per-hour slots) into design's { day: [hours] }.
const availabilityToMockMap = (slots) => {
  const map = { 0:[], 1:[], 2:[], 3:[], 4:[], 5:[], 6:[] };
  for (const s of slots || []) {
    const md = realDayToMockDay(s.dayOfWeek);
    const startH = parseInt(String(s.startTime).slice(0, 2), 10);
    const endH   = parseInt(String(s.endTime).slice(0, 2), 10);
    for (let h = startH; h < endH; h++) {
      if (!map[md].includes(h)) map[md].push(h);
    }
    map[md].sort((a, b) => a - b);
  }
  return map;
};

const mockMapToAvailabilityRows = (map) => {
  const rows = [];
  for (let md = 0; md < 7; md++) {
    const hours = (map[md] || []).slice().sort((a,b) => a-b);
    for (const h of hours) {
      rows.push({
        dayOfWeek: mockDayToRealDay(md),
        startTime: `${String(h).padStart(2,'0')}:00:00`,
        endTime:   `${String(h+1).padStart(2,'0')}:00:00`,
      });
    }
  }
  return rows;
};

const instInput = {
  width:'100%', padding:'12px 12px', borderRadius:8,
  border:'1.5px solid oklch(88% 0.015 265)', fontSize:16,
  fontFamily:"'Plus Jakarta Sans', sans-serif",
  color:'oklch(22% 0.06 265)', background:'#fff', outline:'none', boxSizing:'border-box', minHeight:44,
};
const instLabel = {
  display:'block', fontSize:10, fontWeight:700,
  textTransform:'uppercase', letterSpacing:'0.06em',
  color:'oklch(52% 0.04 265)', marginBottom:5,
};

// ── Login (auth) ────────────────────────────────────────────────────
// Magic-link based: instructor enters email, gets a click-to-login email.
const InstructorLogin = ({ onLogin, onBack }) => {
  const [email, setEmail] = React.useState('');
  const [err,   setErr]   = React.useState('');
  const [busy,  setBusy]  = React.useState(false);
  const [sent,  setSent]  = React.useState(false);
  // hCaptcha — Supabase has captcha enforcement on, so the magic-link send
  // must carry a token. Without it the request is rejected with
  // "captcha protection: request disallowed (no captcha_token found)". Same
  // widget + token the student login uses.
  const captcha = window.useCaptcha ? window.useCaptcha() : { token: null, widget: null, required: false };

  const submit = async (e) => {
    e.preventDefault();
    if (captcha.required) { setErr('Please complete the captcha.'); return; }
    setErr(''); setBusy(true);
    try {
      const { error } = await window.AUTH.sendMagicLink({ email: email.trim(), captchaToken: captcha.token });
      // hCaptcha tokens are single-use — refresh after the attempt so a retry
      // (e.g. after a typo'd email) gets a fresh challenge rather than
      // "already-seen-response".
      captcha.reset && captcha.reset();
      if (error) { setErr(error.message || "Couldn't send magic link."); return; }
      setSent(true);
    } finally { setBusy(false); }
  };

  // Mirror of the student login's cross-link: a student who landed on the
  // instructor login (e.g. followed a stale ?page=instructor-portal link) gets
  // a one-click path back to the student login. getInitialPage honors
  // ?page=student-portal.
  const goStudentLogin = () => {
    try { window.location.assign(window.location.pathname + '?page=student-portal' + window.location.hash); }
    catch (_) { window.location.assign('/?page=student-portal'); }
  };

  return (
    <div style={{ minHeight:'100vh', display:'flex', alignItems:'center', justifyContent:'center', background:'oklch(98.5% 0.007 60)', fontFamily:"'Plus Jakarta Sans', sans-serif", position:'relative' }}>
      <button onClick={onBack} aria-label="Close" title="Back to site"
        style={{ position:'absolute', top:18, right:18, width:38, height:38, borderRadius:'50%', background:'oklch(95% 0.005 60)', border:'1px solid oklch(90% 0.01 265)', cursor:'pointer', fontSize:18, lineHeight:1, color:'oklch(40% 0.04 265)', fontFamily:"'Plus Jakarta Sans', sans-serif", display:'flex', alignItems:'center', justifyContent:'center', zIndex:10 }}>
        ×
      </button>
      <div style={{ width:340 }}>
        <div style={{ fontFamily:"'Cormorant Garamond', serif", fontSize:20, fontWeight:700, letterSpacing:'0.15em', color:'oklch(22% 0.06 265)', marginBottom:40, textAlign:'center' }}>COACHING</div>
        <div style={{ fontSize:15, fontWeight:600, color:'oklch(18% 0.04 265)', marginBottom:3 }}>Instructor login</div>
        <div style={{ fontSize:12, color:'oklch(60% 0.03 265)', marginBottom:14, lineHeight:1.5 }}>Your schedule, students &amp; balance.</div>
        {!sent && (
          <div style={{ fontSize:12.5, color:'oklch(50% 0.04 265)', marginBottom:24, lineHeight:1.5 }}>
            Are you a student?{' '}
            <button type="button" onClick={goStudentLogin}
              style={{ background:'none', border:'none', padding:0, color:'oklch(48% 0.18 265)', cursor:'pointer', fontWeight:700, fontSize:12.5, textDecoration:'underline', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>
              Log in here →
            </button>
          </div>
        )}
        {sent ? (
          <div style={{ fontSize:13, color:'oklch(38% 0.04 265)', lineHeight:1.7, marginBottom:20 }}>📧 Check your inbox at <strong>{email}</strong>. Click the link to sign in. The tab will reload automatically.</div>
        ) : (
          <form onSubmit={submit}>
            <div style={{ marginBottom:14 }}>
              <input type="email" value={email} onChange={e => { setEmail(e.target.value); setErr(''); }} placeholder="Your email" style={instInput} autoFocus />
              {err && <div style={{ fontSize:11, color:'oklch(40% 0.1 25)', marginTop:5 }}>{err}</div>}
            </div>
            {captcha.widget}
            <button type="submit" disabled={busy || !email.includes('@') || captcha.required} style={{ width:'100%', background:'oklch(22% 0.06 265)', color:'#fff', border:'none', borderRadius:9, padding:'12px 0', fontWeight:600, fontSize:14, cursor:busy?'wait':'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif", opacity:(busy||captcha.required)?0.72:1 }}>
              {busy ? 'Sending…' : '📧 Send magic link'}
            </button>
          </form>
        )}
        <div style={{ textAlign:'center', marginTop:20 }}>
          <button onClick={onBack} style={{ background:'none', border:'none', fontSize:13, color:'oklch(60% 0.03 265)', cursor:'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>← Back to site</button>
        </div>
      </div>
    </div>
  );
};

// ── Add Lesson Modal (teacher adds an assigned student to calendar) ─
// Now supports a "recurring weekly for N weeks" toggle. When recurring,
// we call createRecurringSeries instead of creating a single booking, so
// every week's lesson lands on the calendar in one shot.
const InstructorPortal = ({ onBack, setPage }) => {
  const auth = window.useAuth();
  const data = window.useDashboardData();
  // useIsMobile MUST live at the top so the hook count is stable across
  // every render. Calling it inside `if (view === 'pending')` (the prior
  // shape) caused "Rendered more hooks than during the previous render"
  // when the view transitioned from 'checking' → 'pending', which React
  // recovers from by unmounting the component → blank page on X-exit.
  // Found 2026-05-21 by the x-blank-bug Playwright repro.
  const isMobile = window.useIsMobile ? window.useIsMobile() : (typeof window !== 'undefined' && window.innerWidth < 768);
  const [view, setView] = React.useState('checking');
  // 'pending' view shows when the instructor's profile_status isn't 'approved'
  // (draft / pending_review / rejected). They get a placeholder screen with
  // a CTA to continue the wizard — NOT the full schedule UI, which they
  // haven't earned yet. Found 2026-05-21: pressing X mid-wizard dropped the
  // teacher into the full dashboard as if they were already approved.
  const [pendingState, setPendingState] = React.useState(null);

  React.useEffect(() => {
    if (auth.loading) { setView('checking'); return; }
    if (!auth.user) { setView('login'); return; }
    // Admin View-As: same pattern as StudentPortal — when app.jsx mounts us
    // with window.MASTERY.viewAs set to a teacher, skip the role gate (the
    // admin's own profile.role is null/'admin') and render the schedule.
    if (window.MASTERY?.viewAs?.kind === 'instructor') {
      data.refresh();
      setView('schedule');
      return;
    }
    // FLASH FIX: same race as StudentPortal — auth.loading flips false a
    // moment before the profile/admin lookups finish. Hold on 'checking' so
    // the instructor login UI doesn't flash for a frame on magic-link
    // landing or hard refresh.
    if (auth.user && !auth.profile && !auth.isAdmin) { setView('checking'); return; }
    if (auth.profile?.role === 'instructor') {
      // Look up profile_status + signup_progress before letting them into
      // the dashboard. Approved -> full dashboard. Anything else -> the
      // pending-application placeholder.
      (async () => {
        const { data: instr } = await window.supa.from('instructors')
          .select('profile_status').eq('user_id', auth.user.id).maybeSingle();
        const { data: prog } = await window.supa.from('instructor_signup_progress')
          .select('review_status, rejection_reason, submitted_at, last_edited_at, current_step, subjects_completed_at, how_it_works_completed_at, basic_info_completed_at, profile_completed_at, agreement_completed_at')
          .eq('instructor_id', auth.profile.id).maybeSingle();
        const status = instr?.profile_status || 'draft';
        if (status === 'approved') {
          data.refresh();
          setView('schedule');
        } else {
          setPendingState({ status, progress: prog });
          setView('pending');
        }
      })();
    } else if (auth.profile?.role === 'student') {
      setView('wrong-role');
    } else {
      setView('login');
    }
  }, [auth.loading, auth.user?.id, auth.profile?.role, auth.isAdmin]);

  const handleSignOut = async () => {
    // View-As: don't log the admin out when they click "Sign out" inside
    // the embedded teacher dashboard — just exit the view. See the
    // matching guard in StudentPortal for the full rationale.
    if (window.MASTERY?.viewAs) { onBack(); return; }
    try { await window.supa.auth.signOut(); } catch (e) {}
    onBack();
  };

  if (view === 'checking') {
    return <div style={{ minHeight:'100vh', display:'flex', alignItems:'center', justifyContent:'center', background:'oklch(98.5% 0.007 60)', color:'oklch(55% 0.03 265)', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>Loading…</div>;
  }
  if (view === 'wrong-role') {
    return (
      <div style={{ minHeight:'100vh', display:'flex', alignItems:'center', justifyContent:'center', background:'oklch(98.5% 0.007 60)', fontFamily:"'Plus Jakarta Sans', sans-serif", padding:'24px' }}>
        <div style={{ maxWidth:400, textAlign:'center' }}>
          <div style={{ fontFamily:"'Cormorant Garamond', serif", fontSize:22, fontWeight:700, color:'oklch(22% 0.06 265)', marginBottom:14 }}>Wrong portal</div>
          <div style={{ fontSize:15, color:'oklch(50% 0.03 265)', marginBottom:24, lineHeight:1.7 }}>You're signed in as a student. Sign out below to access the instructor portal.</div>
          <button onClick={handleSignOut} style={{ background:'oklch(22% 0.06 265)', color:'#fff', border:'none', borderRadius:10, padding:'14px 28px', fontWeight:600, fontSize:15, cursor:'pointer', fontFamily:"'Plus Jakarta Sans', sans-serif" }}>Sign out</button>
        </div>
      </div>
    );
  }
  if (view === 'pending') {
    const status   = pendingState?.status || 'draft';
    const prog     = pendingState?.progress;
    const steps = [
      { k: 'subjects_completed_at',     label: 'Subjects' },
      { k: 'how_it_works_completed_at', label: 'How it works' },
      { k: 'basic_info_completed_at',   label: 'Basic info' },
      { k: 'profile_completed_at',      label: 'Profile' },
      { k: 'agreement_completed_at',    label: 'Agreement' },
      { k: 'submitted_at',              label: 'Submit' },
    ];
    const done = steps.filter(s => prog && prog[s.k]).length;
    const conf =
      status === 'pending_review' ? { tone:'amber',  title:'Your application is under review',
        body:'Thanks for applying — our team is reviewing your profile. You\'ll hear from us by email within 3–5 business days.',
        cta:'Edit my application' } :
      status === 'rejected'       ? { tone:'red',    title:'Your application wasn\'t approved',
        body: prog?.rejection_reason || 'Please review your application and submit again. We\'ll re-review the new version.',
        cta:'Edit + resubmit' } :
                                    { tone:'blue',   title:'Your application is not complete yet',
        body:'You can finish your tutor application any time. Pick up where you left off below.',
        cta:'Continue application' };
    const toneCss = {
      amber: { bg:'oklch(96% 0.07 80)',  fg:'oklch(34% 0.14 80)',  border:'oklch(86% 0.1 80)' },
      red:   { bg:'oklch(95% 0.06 25)',  fg:'oklch(40% 0.15 25)',  border:'oklch(88% 0.06 25)' },
      blue:  { bg:'oklch(95% 0.04 265)', fg:'oklch(35% 0.12 265)', border:'oklch(85% 0.05 265)' },
    }[conf.tone];

    return (
      <div style={{ minHeight:'100vh', background:'oklch(98.5% 0.007 60)', fontFamily:"'Plus Jakarta Sans', sans-serif", padding: isMobile ? '24px 16px' : '60px 24px' }}>
        <div style={{ maxWidth:560, margin:'0 auto' }}>
          <div style={{ background:'#fff', border:`1px solid ${toneCss.border}`, borderRadius:14, padding: isMobile ? 22 : 32, marginBottom:18 }}>
            <div style={{ display:'inline-block', padding:'4px 10px', borderRadius:14, fontSize:11, fontWeight:700, background:toneCss.bg, color:toneCss.fg, textTransform:'uppercase', letterSpacing:'0.05em', marginBottom:14 }}>
              {status.replace('_', ' ')}
            </div>
            <h1 style={{ fontFamily:"'Cormorant Garamond', serif", fontSize: isMobile ? 24 : 28, fontWeight:700, color:'oklch(22% 0.06 265)', margin:'0 0 10px', lineHeight:1.2 }}>
              {conf.title}
            </h1>
            <p style={{ fontSize:15, color:'oklch(40% 0.04 265)', lineHeight:1.6, margin:'0 0 22px' }}>
              {conf.body}
            </p>

            <div style={{ marginBottom:22 }}>
              <div style={{ display:'flex', justifyContent:'space-between', fontSize:12, color:'oklch(50% 0.03 265)', marginBottom:6 }}>
                <span>Progress</span><span>{done} of {steps.length} steps</span>
              </div>
              <div style={{ height:6, background:'oklch(94% 0.01 265)', borderRadius:3, overflow:'hidden' }}>
                <div style={{ width:`${(done / steps.length) * 100}%`, height:'100%', background:'oklch(72% 0.17 80)' }} />
              </div>
              <div style={{ marginTop:10, display:'flex', flexWrap:'wrap', gap:6 }}>
                {steps.map(s => {
                  const ok = prog && prog[s.k];
                  return (
                    <span key={s.k} style={{ fontSize:11, padding:'3px 8px', borderRadius:8, background: ok ? 'oklch(94% 0.07 155)' : 'oklch(96% 0.008 265)', color: ok ? 'oklch(30% 0.13 150)' : 'oklch(50% 0.03 265)', fontWeight:600 }}>
                      {ok ? '✓' : '○'} {s.label}
                    </span>
                  );
                })}
              </div>
            </div>

            <button onClick={() => setPage && setPage('become-instructor')} style={{
              width:'100%', background:'oklch(22% 0.06 265)', color:'#fff', border:'none', borderRadius:10,
              padding: isMobile ? '14px 18px' : '14px 26px', fontWeight:700, fontSize:15, cursor:'pointer',
              fontFamily:"'Plus Jakarta Sans', sans-serif",
            }}>{conf.cta} →</button>
          </div>

          <div style={{ display:'flex', justifyContent:'center', gap:14, fontSize:13, color:'oklch(50% 0.03 265)' }}>
            <button onClick={() => setPage && setPage('home')} style={{ background:'none', border:'none', color:'inherit', cursor:'pointer', textDecoration:'underline', padding:8 }}>Back to home</button>
            <button onClick={handleSignOut} style={{ background:'none', border:'none', color:'inherit', cursor:'pointer', textDecoration:'underline', padding:8 }}>Sign out</button>
          </div>
        </div>
      </div>
    );
  }
  if (view === 'schedule') return <window.InstructorScheduleList onBack={handleSignOut} setPage={setPage} />;
  return <InstructorLogin onLogin={() => setView('schedule')} onBack={onBack} />;
};

// ── Teacher → minimal student row (collapsible) ────────────────────
// Joe wants a very thin list of "your students" with: next lesson +
// every session note. Tap to expand. No personal info, no rates, no
// payment — just the bare minimum for context.
Object.assign(window, { InstructorPortal });
