/* global React, AdmIcons */
// Content panel (BUILD_PLAN.md 2.4 + 4.1-4.3): the module → lesson tree on the left,
// an editor for whatever is selected on the right. Reads come from the
// list-lesson-content Edge Function (RLS hides lessons/documents from admins on the
// client), every write goes through manage-content, and video uploads go straight
// to Bunny via the upload-video credential flow. Reorder is up/down buttons, no DnD.

const { useState: useCtState, useEffect: useCtEffect } = React;

const DOC_ACCEPT = '.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.zip,.png,.jpg,.jpeg,.gif,.webp';
const DOC_MAX_BYTES = 50 * 1024 * 1024;

// Same shape/behavior as admin-detail.jsx's invokeAdminFn -- kept local since these
// admin files don't share a common module system beyond the window.* atoms.
async function invokeContentFn(name, body) {
  const { data, error } = await window.supabaseClient.functions.invoke(name, { body });
  if (error) {
    let msg = error.message || 'Request failed.';
    try { const b = await error.context?.json(); if (b?.error) msg = b.error; } catch (_) {}
    return { ok: false, error: msg };
  }
  return { ok: true, data };
}
const manageContent = (action, body) => invokeContentFn('manage-content', { action, ...body });

// Two-click delete: first click arms it, second confirms. Cheap, keyboard-friendly,
// and enough friction for an irreversible action inside an admin-only screen.
function ArmedDelete({ label, note, busy, onConfirm }) {
  const [armed, setArmed] = useCtState(false);
  return (
    <div className="adm-danger-zone">
      <label>{label}</label>
      <div className="adm-danger-note">{note}</div>
      <div style={{ display: 'flex', gap: 10 }}>
        {armed && <button className="adm-action" disabled={busy} onClick={() => setArmed(false)}>Keep it</button>}
        <button
          className="adm-action danger"
          disabled={busy}
          onClick={() => armed ? onConfirm() : setArmed(true)}
        >
          {busy ? 'Deleting…' : armed ? 'Yes, delete permanently' : label}
        </button>
      </div>
    </div>
  );
}

function ContentMsg({ msg }) {
  if (!msg) return null;
  return <div className={msg.kind === 'err' ? 'adm-dialog-error' : 'adm-content-ok'} role="alert">{msg.text}</div>;
}

// --- Module editor -------------------------------------------------------------

function ModulePanel({ module, lessonCount, onSaved, onDeleted }) {
  const isNew = !module;
  const [code, setCode]   = useCtState(module?.code || '');
  const [title, setTitle] = useCtState(module?.title || '');
  const [busy, setBusy]   = useCtState('');
  const [msg, setMsg]     = useCtState(null);

  async function save() {
    if (busy) return;
    setBusy('save'); setMsg(null);
    const r = isNew
      ? await manageContent('module.create', { code, title })
      : await manageContent('module.update', { id: module.id, code, title });
    setBusy('');
    if (!r.ok) { setMsg({ kind: 'err', text: r.error }); return; }
    setMsg({ kind: 'ok', text: isNew ? 'Module created.' : 'Module saved.' });
    onSaved(r.data.module);
  }

  async function remove() {
    setBusy('delete'); setMsg(null);
    const r = await manageContent('module.delete', { id: module.id });
    setBusy('');
    if (!r.ok) { setMsg({ kind: 'err', text: r.error }); return; }
    onDeleted();
  }

  return (
    <React.Fragment>
      <h3>{isNew ? 'New module' : `${module.code} — ${module.title}`}</h3>
      <div className="sub">{isNew ? 'Added to the end of the module list. Students see it as locked until granted access.' : `${lessonCount} lesson${lessonCount === 1 ? '' : 's'}`}</div>

      <div className="adm-field-row">
        <div className="adm-field" style={{ flex: '0 0 140px' }}>
          <label>Code</label>
          <input value={code} onChange={e => setCode(e.target.value)} placeholder="309" maxLength={20} />
        </div>
        <div className="adm-field" style={{ flex: 1 }}>
          <label>Title</label>
          <input value={title} onChange={e => setTitle(e.target.value)} placeholder="Module title" maxLength={200} />
        </div>
      </div>

      <ContentMsg msg={msg} />
      <div className="adm-dialog-actions">
        <button className="adm-btn-glow" onClick={save} disabled={!!busy || !code.trim() || !title.trim()}>
          {busy === 'save' ? 'Saving…' : isNew ? 'Create module' : 'Save changes'}
        </button>
      </div>

      {!isNew && (
        <ArmedDelete
          label="Delete module"
          note="Removes the module, all its lessons, their videos and documents, and every student's progress and access for it."
          busy={busy === 'delete'}
          onConfirm={remove}
        />
      )}
    </React.Fragment>
  );
}

// --- Lesson editor -------------------------------------------------------------

function LessonPanel({ lesson, module, documents, onSaved, onDeleted, onDocsChanged }) {
  const isNew = !lesson;
  const [n, setN]         = useCtState(lesson?.n || '');
  const [title, setTitle] = useCtState(lesson?.title || '');
  const [tag, setTag]     = useCtState(lesson?.tag || '');
  const [divider, setDivider] = useCtState(lesson?.divider_label || '');
  const [busy, setBusy]   = useCtState('');
  const [msg, setMsg]     = useCtState(null);

  async function save() {
    if (busy) return;
    setBusy('save'); setMsg(null);
    const r = isNew
      ? await manageContent('lesson.create', { module_id: module.id, n, title, tag, divider_label: divider })
      : await manageContent('lesson.update', { id: lesson.id, n, title, tag, divider_label: divider });
    setBusy('');
    if (!r.ok) { setMsg({ kind: 'err', text: r.error }); return; }
    setMsg({ kind: 'ok', text: isNew ? 'Lesson created.' : 'Lesson saved.' });
    onSaved(r.data.lesson);
  }

  async function remove() {
    setBusy('delete'); setMsg(null);
    const r = await manageContent('lesson.delete', { id: lesson.id });
    setBusy('');
    if (!r.ok) { setMsg({ kind: 'err', text: r.error }); return; }
    onDeleted();
  }

  return (
    <React.Fragment>
      <h3>{isNew ? `New lesson in ${module.code}` : `${module.code} / ${lesson.n} — ${lesson.title}`}</h3>
      <div className="sub">{isNew ? 'Added to the end of this module.' : (lesson.tag || 'No tag')}</div>

      <div className="adm-content-section">
        <h4>Details</h4>
        <div className="adm-field-row">
          <div className="adm-field" style={{ flex: '0 0 100px' }}>
            <label>Number</label>
            <input value={n} onChange={e => setN(e.target.value)} placeholder="01" maxLength={20} />
          </div>
          <div className="adm-field" style={{ flex: 1 }}>
            <label>Title</label>
            <input value={title} onChange={e => setTitle(e.target.value)} placeholder="Lesson title" maxLength={200} />
          </div>
        </div>
        <div className="adm-field">
          <label>Tag <span className="hint">· shown under the title, e.g. "Introduction Phase I"</span></label>
          <input value={tag} onChange={e => setTag(e.target.value)} placeholder="Optional" maxLength={200} />
        </div>
        <div className="adm-field">
          <label>Divider above <span className="hint">· starts a new section in the lesson list, e.g. "Part 2". Leave blank for none</span></label>
          <input value={divider} onChange={e => setDivider(e.target.value)} placeholder="Optional" maxLength={100} />
        </div>
        <ContentMsg msg={msg} />
        <div className="adm-dialog-actions">
          <button className="adm-btn-glow" onClick={save} disabled={!!busy || !n.trim() || !title.trim()}>
            {busy === 'save' ? 'Saving…' : isNew ? 'Create lesson' : 'Save changes'}
          </button>
        </div>
      </div>

      {!isNew && (
        <React.Fragment>
          <VideoSection lesson={lesson} onUploaded={onSaved} />
          <DocumentsSection lesson={lesson} documents={documents} onChanged={onDocsChanged} />
          <ArmedDelete
            label="Delete lesson"
            note="Removes the lesson, its video and documents, and every student's progress on it."
            busy={busy === 'delete'}
            onConfirm={remove}
          />
        </React.Fragment>
      )}
    </React.Fragment>
  );
}

// --- Video (unchanged flow from 2.4: TUS upload straight to Bunny) ----------------

function VideoSection({ lesson, onUploaded }) {
  const [file, setFile]   = useCtState(null);
  const [phase, setPhase] = useCtState('idle'); // idle | uploading | confirming | error
  const [pct, setPct]     = useCtState(0);
  const [msg, setMsg]     = useCtState(null);
  const inFlight = phase === 'uploading' || phase === 'confirming';

  function upload() {
    if (!file || inFlight) return;
    setMsg(null); setPct(0); setPhase('uploading');

    (async () => {
      const cred = await invokeContentFn('upload-video', { lesson_id: lesson.id, step: 'create' });
      if (!cred.ok) { setPhase('error'); setMsg({ kind: 'err', text: cred.error }); return; }
      const { video_id, library_id, expires, signature } = cred.data;

      const tusUpload = new window.tus.Upload(file, {
        endpoint: 'https://video.bunnycdn.com/tusupload',
        retryDelays: [0, 3000, 5000, 10000, 20000],
        headers: {
          AuthorizationSignature: signature,
          AuthorizationExpire: String(expires),
          VideoId: video_id,
          LibraryId: String(library_id),
        },
        metadata: { filetype: file.type || 'video/mp4', title: file.name },
        onError: (err) => { setPhase('error'); setMsg({ kind: 'err', text: err.message || 'Upload failed.' }); },
        onProgress: (sent, total) => setPct(Math.round((sent / total) * 100)),
        onSuccess: async () => {
          setPhase('confirming');
          const confirm = await invokeContentFn('upload-video', {
            lesson_id: lesson.id, bunny_video_id: video_id, step: 'confirm',
          });
          if (!confirm.ok) { setPhase('error'); setMsg({ kind: 'err', text: confirm.error }); return; }
          setPhase('idle'); setFile(null);
          setMsg({ kind: 'ok', text: 'Video uploaded and saved to the lesson.' });
          onUploaded({ ...lesson, bunny_video_id: video_id });
        },
      });
      tusUpload.start();
    })();
  }

  return (
    <div className="adm-content-section">
      <h4>Video</h4>
      <div className={`adm-content-video-status ${lesson.bunny_video_id ? 'has-video' : 'no-video'}`}>
        <span className="dot" />
        {lesson.bunny_video_id ? 'Video uploaded' : 'No video uploaded yet'}
      </div>
      <div className="adm-field">
        <label>{lesson.bunny_video_id ? 'Replace video' : 'Upload video'}</label>
        <input type="file" accept="video/*" disabled={inFlight}
          onChange={e => { setFile(e.target.files?.[0] || null); setMsg(null); }} />
      </div>
      {inFlight && (
        <div className="adm-progress">
          <div className="adm-progress-fill" style={{ width: `${phase === 'confirming' ? 100 : pct}%` }} />
        </div>
      )}
      <ContentMsg msg={msg} />
      <div className="adm-dialog-actions">
        <button className="adm-btn-glow" onClick={upload} disabled={!file || inFlight}>
          {phase === 'uploading' ? `Uploading… ${pct}%` : phase === 'confirming' ? 'Saving…' : 'Upload'}
        </button>
      </div>
    </div>
  );
}

// --- Documents (4.3): signed upload URL → Storage → confirm row -------------------

function DocumentsSection({ lesson, documents, onChanged }) {
  const [label, setLabel] = useCtState('');
  const [kind, setKind]   = useCtState('template');
  const [file, setFile]   = useCtState(null);
  const [busy, setBusy]   = useCtState('');
  const [msg, setMsg]     = useCtState(null);
  const [fileKey, setFileKey] = useCtState(0); // bumps to reset the file input after upload

  const isPdf = name => /\.pdf$/i.test(name || '');

  function pickFile(e) {
    const f = e.target.files?.[0] || null;
    setFile(f); setMsg(null);
    if (f && !label) setLabel(f.name.replace(/\.[^.]+$/, ''));
    if (f && !isPdf(f.name)) setKind('extra'); // templates are PDF-only
  }

  async function upload() {
    if (!file || busy) return;
    if (file.size > DOC_MAX_BYTES) { setMsg({ kind: 'err', text: 'File is too large — the limit is 50 MB.' }); return; }
    setBusy('upload'); setMsg(null);

    const prep = await manageContent('document.create', { lesson_id: lesson.id, filename: file.name, size: file.size });
    if (!prep.ok) { setBusy(''); setMsg({ kind: 'err', text: prep.error }); return; }

    const { error: upErr } = await window.supabaseClient.storage
      .from('documents')
      .uploadToSignedUrl(prep.data.file_path, prep.data.token, file, { contentType: file.type || 'application/octet-stream' });
    if (upErr) { setBusy(''); setMsg({ kind: 'err', text: `Upload failed: ${upErr.message}` }); return; }

    const confirm = await manageContent('document.confirm', {
      lesson_id: lesson.id, file_path: prep.data.file_path, filename: file.name, label: label.trim() || file.name, kind,
    });
    setBusy('');
    if (!confirm.ok) { setMsg({ kind: 'err', text: confirm.error }); return; }
    setFile(null); setLabel(''); setFileKey(k => k + 1);
    setMsg({ kind: 'ok', text: 'Document uploaded.' });
    onChanged();
  }

  async function setDocKind(doc, next) {
    if (busy || doc.kind === next) return;
    setBusy(doc.id); setMsg(null);
    const r = await manageContent('document.update', { id: doc.id, label: doc.label, kind: next });
    setBusy('');
    if (!r.ok) { setMsg({ kind: 'err', text: r.error }); return; }
    onChanged();
  }

  async function removeDoc(doc) {
    if (busy) return;
    setBusy(doc.id); setMsg(null);
    const r = await manageContent('document.delete', { id: doc.id });
    setBusy('');
    if (!r.ok) { setMsg({ kind: 'err', text: r.error }); return; }
    onChanged();
  }

  return (
    <div className="adm-content-section">
      <h4>Documents <span className="hint">· Templates (PDF only, previewed in the lesson) and Extra (download) tabs</span></h4>

      {documents.length > 0 && (
        <div className="adm-doc-list">
          {documents.map(d => (
            <div key={d.id} className="adm-doc-row">
              <AdmIcons.File size={14} />
              <div className="name">
                {d.label}
                <span className="file">{d.filename}</span>
              </div>
              <div className="adm-kind-pick">
                {['template', 'extra'].map(k => (
                  <button key={k} className={d.kind === k ? 'on' : ''} disabled={!!busy || (k === 'template' && !isPdf(d.filename))}
                    title={k === 'template' && !isPdf(d.filename) ? 'Templates must be PDF' : undefined}
                    onClick={() => setDocKind(d, k)}>{k}</button>
                ))}
              </div>
              <button className="adm-icon-btn danger" title="Delete document" disabled={!!busy} onClick={() => removeDoc(d)}>
                <AdmIcons.Trash size={13} />
              </button>
            </div>
          ))}
        </div>
      )}
      {documents.length === 0 && <div className="adm-content-empty" style={{ padding: '4px 0 14px' }}>No documents yet.</div>}

      <div className="adm-doc-add">
        <div className="adm-field">
          <label>File <span className="hint">· pdf, doc, xls, ppt, zip or image · 50 MB max</span></label>
          <input key={fileKey} type="file" accept={DOC_ACCEPT} disabled={!!busy} onChange={pickFile} />
        </div>
        <div className="adm-field-row">
          <div className="adm-field" style={{ flex: 1 }}>
            <label>Label</label>
            <input value={label} onChange={e => setLabel(e.target.value)} placeholder="Shown to students" maxLength={200} />
          </div>
          <div className="adm-field" style={{ flex: '0 0 200px' }}>
            <label>Tab</label>
            <div className="adm-role-pick two">
              {['template', 'extra'].map(k => (
                <button key={k} className={kind === k ? 'on' : ''} disabled={k === 'template' && file && !isPdf(file.name)}
                  onClick={() => setKind(k)}>{k}</button>
              ))}
            </div>
          </div>
        </div>
        <ContentMsg msg={msg} />
        <div className="adm-dialog-actions">
          <button className="adm-btn-glow" onClick={upload} disabled={!file || !!busy}>
            {busy === 'upload' ? 'Uploading…' : 'Upload document'}
          </button>
        </div>
      </div>
    </div>
  );
}

// --- Container ----------------------------------------------------------------

function AdminContent() {
  const [modules, setModules]     = useCtState([]);
  const [lessons, setLessons]     = useCtState([]);
  const [documents, setDocuments] = useCtState([]);
  const [loading, setLoading]     = useCtState(true);
  const [loadError, setLoadError] = useCtState('');
  // { type: 'module'|'lesson', id } | { type: 'new-module' } | { type: 'new-lesson', moduleId }
  const [sel, setSel]   = useCtState(null);
  const [moving, setMoving] = useCtState(false);
  const [moveError, setMoveError] = useCtState('');

  async function load({ initial = false } = {}) {
    const r = await invokeContentFn('list-lesson-content', {});
    setLoading(false);
    if (!r.ok) { setLoadError(r.error); return; }
    setLoadError('');
    setModules(r.data.modules || []);
    setLessons(r.data.lessons || []);
    setDocuments(r.data.documents || []);
    // Default selection: the first lesson of the first module (lessons arrive
    // ordered by `order` alone, so [0] would be "some module's lesson 1").
    if (initial) {
      const mods = r.data.modules || [];
      const first = (r.data.lessons || []).find(l => l.module_id === mods[0]?.id);
      setSel(first ? { type: 'lesson', id: first.id } : mods[0] ? { type: 'module', id: mods[0].id } : null);
    }
  }
  useCtEffect(() => { load({ initial: true }); }, []);

  // Phones stack the edit panel under the whole tree, so bring it into view when the
  // admin picks something (skipping the default selection made on first load).
  const panelRef = React.useRef(null);
  const pickedRef = React.useRef(false);
  const selKey = sel ? `${sel.type}:${sel.id || sel.moduleId || ''}` : '';
  useCtEffect(() => {
    if (!selKey) return;
    if (!pickedRef.current) { pickedRef.current = true; return; }
    if (window.matchMedia('(max-width: 900px), (max-height: 500px)').matches) {
      panelRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }
  }, [selKey]);

  async function move(kind, id, direction) {
    if (moving) return;
    setMoving(true); setMoveError('');
    const r = await manageContent(`${kind}.move`, { id, direction });
    if (!r.ok) setMoveError(r.error);
    await load();
    setMoving(false);
  }

  const lessonsOf = (m) => lessons.filter(l => l.module_id === m.id);
  const selModule = sel?.type === 'module' ? modules.find(m => m.id === sel.id) : null;
  const selLesson = sel?.type === 'lesson' ? lessons.find(l => l.id === sel.id) : null;
  const newLessonModule = sel?.type === 'new-lesson' ? modules.find(m => m.id === sel.moduleId) : null;

  if (loading) return <div className="adm-content"><div className="adm-content-empty">Loading content…</div></div>;
  if (loadError) return <div className="adm-content"><div className="adm-content-empty err">{loadError}</div></div>;

  // Plain render helper (not a component) so the buttons aren't remounted every render.
  const tools = (kind, id, first, last) => (
    <span className="adm-content-tools" onClick={e => e.stopPropagation()}>
      <button className="adm-icon-btn" title="Move up" disabled={moving || first} onClick={() => move(kind, id, 'up')}><AdmIcons.Up size={12} /></button>
      <button className="adm-icon-btn" title="Move down" disabled={moving || last} onClick={() => move(kind, id, 'down')}><AdmIcons.Down size={12} /></button>
    </span>
  );

  return (
    <div className="adm-content">
      <div className="adm-content-list">
        {moveError && <div className="adm-content-empty err">{moveError}</div>}
        {modules.map((m, mi) => {
          const modLessons = lessonsOf(m);
          return (
            <div key={m.id} className="adm-content-mod">
              <div
                role="button" tabIndex={0}
                className={`adm-content-mod-head ${selModule?.id === m.id ? 'on' : ''}`}
                onClick={() => setSel({ type: 'module', id: m.id })}
                onKeyDown={e => e.key === 'Enter' && setSel({ type: 'module', id: m.id })}
              >
                <span className="lbl">{m.code} · {m.title}</span>
                {tools('module', m.id, mi === 0, mi === modules.length - 1)}
              </div>
              {modLessons.map((l, li) => (
                <React.Fragment key={l.id}>
                {l.divider_label && (
                  <div className="adm-lesson-divider" onClick={() => setSel({ type: 'lesson', id: l.id })}>
                    <span>{l.divider_label}</span>
                  </div>
                )}
                <div
                  role="button" tabIndex={0}
                  className={`adm-lesson-row ${selLesson?.id === l.id ? 'on' : ''}`}
                  onClick={() => setSel({ type: 'lesson', id: l.id })}
                  onKeyDown={e => e.key === 'Enter' && setSel({ type: 'lesson', id: l.id })}
                >
                  <span>
                    <span className="n">{l.n}</span>
                    <span className="t">{l.title}</span>
                  </span>
                  <span className="adm-lesson-row-right">
                    <span className={`adm-content-video-dot ${l.bunny_video_id ? 'has' : ''}`} title={l.bunny_video_id ? 'Video uploaded' : 'No video yet'} />
                    {tools('lesson', l.id, li === 0, li === modLessons.length - 1)}
                  </span>
                </div>
                </React.Fragment>
              ))}
              <button
                className={`adm-content-add ${sel?.type === 'new-lesson' && sel.moduleId === m.id ? 'on' : ''}`}
                onClick={() => setSel({ type: 'new-lesson', moduleId: m.id })}
              >
                <AdmIcons.Plus size={11} /> Add lesson
              </button>
            </div>
          );
        })}
        <button
          className={`adm-content-add mod ${sel?.type === 'new-module' ? 'on' : ''}`}
          onClick={() => setSel({ type: 'new-module' })}
        >
          <AdmIcons.Plus size={11} /> Add module
        </button>
      </div>

      <div className="adm-content-panel" ref={panelRef}>
        {!sel && <div className="adm-content-empty">Select a module or lesson, or add one.</div>}

        {sel?.type === 'new-module' && (
          <ModulePanel key="new-module" module={null}
            onSaved={async (m) => { await load(); setSel({ type: 'module', id: m.id }); }} />
        )}
        {selModule && (
          <ModulePanel key={selModule.id} module={selModule} lessonCount={lessonsOf(selModule).length}
            onSaved={() => load()}
            onDeleted={async () => { setSel(null); await load(); }} />
        )}
        {newLessonModule && (
          <LessonPanel key={`new-lesson-${newLessonModule.id}`} lesson={null} module={newLessonModule} documents={[]}
            onSaved={async (l) => { await load(); setSel({ type: 'lesson', id: l.id }); }} />
        )}
        {selLesson && (
          <LessonPanel key={selLesson.id} lesson={selLesson} module={modules.find(m => m.id === selLesson.module_id)}
            documents={documents.filter(d => d.lesson_id === selLesson.id)}
            onSaved={() => load()}
            onDocsChanged={() => load()}
            onDeleted={async () => { setSel(null); await load(); }} />
        )}
        {sel && !selModule && !selLesson && !newLessonModule && sel.type !== 'new-module' && (
          <div className="adm-content-empty">That item no longer exists.</div>
        )}
      </div>
    </div>
  );
}
window.AdminContent = AdminContent;
