import { Check, Clipboard, Eye, FileDown, Lightbulb, Play, RotateCcw, SquareTerminal } from 'lucide-react';
import React from 'react';
import { LinuxTerminalPro } from '../components/linux-terminal-pro';
import { LearnVideoPlayer } from '../learn/blocks/learn-video-player';
import type { LearnBlock, LearnStarter } from '../learn/types';
import {
  cmsCheckCodeExercise,
  cmsGetSolution,
  cmsGradeCheckpoint,
  cmsResetTerminalTask,
  cmsRunCode,
  cmsRunCodeExercise,
  cmsStartTerminalTask,
  cmsVerifyTerminalTask,
  type CmsInteractiveKind,
  type InteractiveContentDocument,
  type CmsInteractiveState,
} from '../saas/saas-api';

function text(data:Record<string,unknown>,key:string){return typeof data[key]==='string'?String(data[key]):'';}
function number(data:Record<string,unknown>,key:string){return Number(data[key]||0);}
function array(data:Record<string,unknown>,key:string){return Array.isArray(data[key])?data[key] as unknown[]:[];}
function mediaUrl(data:Record<string,unknown>,idKey='mediaId',urlKey='mediaUrl'){const url=text(data,urlKey);if(url)return url;const id=number(data,idKey);return id>0?`/api/learn/media/${id}`:'';}
function safeInlineHtml(input:string):string{if(typeof document==='undefined')return input.replace(/<[^>]*>/gu,'');const doc=new DOMParser().parseFromString(`<div>${input}</div>`,'text/html');const allowed=new Set(['B','STRONG','I','EM','U','S','CODE','A','BR','MARK','SUB','SUP']);for(const el of [...doc.body.querySelectorAll('*')]){if(el.tagName==='DIV')continue;if(!allowed.has(el.tagName)){el.replaceWith(...el.childNodes);continue;}for(const attr of [...el.attributes])if(!(el.tagName==='A'&&attr.name==='href'))el.removeAttribute(attr.name);if(el.tagName==='A'){const href=el.getAttribute('href')||'';if(!/^(https?:|mailto:|\/)/u.test(href))el.removeAttribute('href');else if(/^https?:/u.test(href)){el.setAttribute('rel','noopener noreferrer');el.setAttribute('target','_blank');}else{el.removeAttribute('rel');el.removeAttribute('target');}}}return doc.body.firstElementChild?.innerHTML||'';}
function RichText({html}:{html:string}){return <span dangerouslySetInnerHTML={{__html:safeInlineHtml(html)}}/>;}
function NestedList({items,ordered=false}:{items:unknown[];ordered?:boolean}){const Tag=ordered?'ol':'ul';return <Tag>{items.map((raw,index)=>{const item=typeof raw==='string'?{content:raw,items:[]}:(raw||{}) as {content?:string;text?:string;items?:unknown[]};const children=Array.isArray(item.items)?item.items:[];return <li key={index}><RichText html={String(item.content||item.text||'')}/>{children.length?<NestedList items={children} ordered={ordered}/>:null}</li>})}</Tag>;}
function docsSlug(value:string){return value.trim().toLowerCase().normalize('NFKD').replace(/[^a-z0-9]+/gu,'-').replace(/^-+|-+$/gu,'').slice(0,80)||'section';}

export function interactiveContentToc(document:InteractiveContentDocument|undefined){const used=new Set<string>();const entries:Array<{id:string;label:string;level:2|3}>=[];for(const block of document?.blocks||[]){if(block.type!=='header')continue;const level=Math.min(4,Math.max(2,number(block.data,'level')||2));if(level>3)continue;const label=text(block.data,'text').replace(/<[^>]*>/gu,'').trim();if(!label)continue;const base=docsSlug(label);let id=base,suffix=2;while(used.has(id)){id=`${base}-${suffix++}`;}used.add(id);entries.push({id,label,level:level as 2|3});}return entries;}

export type CmsInteractiveRuntime={
  runCode:(blockId:string,code:string,stdin:string)=>Promise<{exitCode:number;stdout:string;stderr:string;status?:string}>;
  runExercise:(blockId:string,files:Record<string,string>,entryFile:string,stdin:string)=>Promise<{exitCode:number;stdout:string;stderr:string;passed?:boolean}>;
  checkExercise:(blockId:string,files:Record<string,string>,entryFile:string)=>Promise<{passed:boolean;exitCode:number;stdout:string;stderr:string;visibleTests?:Array<{index:number;label:string;passed:boolean}>;hiddenTests?:{passed:number;total:number}}>;
  gradeCheckpoint:(blockId:string,answer:number|number[])=>Promise<{correct:boolean;explanation?:string}>;
  getSolution:(blockId:string)=>Promise<{title:string;content:string}>;
  startTerminalTask:(blockId:string)=>Promise<{attempt:{id:string;attemptNumber:number;projectId:string;generation:number};terminalSession:unknown}>;
  verifyTerminalTask:(blockId:string,attemptId:string)=>Promise<{passed:boolean;message?:string;checks?:Array<{label:string;passed:boolean}>}>;
  resetTerminalTask:(blockId:string,attemptId:string)=>Promise<void>;
};
function defaultRuntime(kind:CmsInteractiveKind,slug:string):CmsInteractiveRuntime{return{
  runCode:(blockId,code,stdin)=>cmsRunCode(kind,slug,blockId,code,stdin),
  runExercise:(blockId,files,entryFile,stdin)=>cmsRunCodeExercise(kind,slug,blockId,files,entryFile,stdin),
  checkExercise:(blockId,files,entryFile)=>cmsCheckCodeExercise(kind,slug,blockId,files,entryFile),
  gradeCheckpoint:(blockId,answer)=>cmsGradeCheckpoint(kind,slug,blockId,answer),
  getSolution:blockId=>cmsGetSolution(kind,slug,blockId),
  startTerminalTask:blockId=>cmsStartTerminalTask(kind,slug,blockId),
  verifyTerminalTask:(blockId,attemptId)=>cmsVerifyTerminalTask(kind,slug,blockId,attemptId),
  resetTerminalTask:(blockId,attemptId)=>cmsResetTerminalTask(kind,slug,blockId,attemptId),
};}


function CmsAuthAction({onAuthRequired,children}:{onAuthRequired:()=>void;children:React.ReactNode}){return <button type="button" className="interactive-button interactive-button-primary" onClick={onAuthRequired}>{children}</button>;}

function RunnableCode({block,kind,slug,authenticated,onAuthRequired,interactive,runtime,blockState}:{block:LearnBlock;kind:CmsInteractiveKind;slug:string;authenticated:boolean;onAuthRequired:(blockId?:string)=>void;interactive:boolean;runtime:CmsInteractiveRuntime;blockState?:CmsInteractiveState['blocks'][string]}){
  const initial=text(block.data,'code');const [code,setCode]=React.useState(initial);const [stdin,setStdin]=React.useState(text(block.data,'stdin'));const [busy,setBusy]=React.useState(false);const [result,setResult]=React.useState<{exitCode:number;stdout:string;stderr:string}>();const [error,setError]=React.useState('');const runnable=block.data.runnable!==false;const allowStdin=block.data.allowStdin===true;
  React.useEffect(()=>{setCode(initial);setStdin(text(block.data,'stdin'));setResult(undefined);setError('')},[initial,block.data.stdin]);
  const run=async()=>{if(!authenticated){onAuthRequired(block.id);return;}setBusy(true);setError('');try{setResult(await runtime.runCode(block.id,code,allowStdin?stdin:''));}catch(reason){setError(reason instanceof Error?reason.message:String(reason));}finally{setBusy(false)}};
  return <section id={`block-${block.id}`} className="interactive-learn-code interactive-learn-code-runnable"><header><span>{text(block.data,'filename')||text(block.data,'language')||'Code'}</span><div><button type="button" onClick={()=>void navigator.clipboard.writeText(code)}><Clipboard className="size-4"/> Copy</button>{runnable&&interactive?(authenticated?<button type="button" disabled={busy} onClick={()=>void run()}><Play className="size-4"/>{busy?'Running…':'Run'}</button>:<CmsAuthAction onAuthRequired={()=>onAuthRequired(block.id)}><Play className="size-4"/> Run</CmsAuthAction>):null}</div></header>{runnable?<><textarea className="interactive-learn-code-editor" spellCheck={false} value={code} onChange={event=>setCode(event.currentTarget.value)}/>{allowStdin?<label className="interactive-learn-code-stdin"><span>Standard input</span><textarea spellCheck={false} value={stdin} onChange={event=>setStdin(event.currentTarget.value)}/></label>:null}</>:<pre><code>{code}</code></pre>}{!interactive&&runnable?<p className="interactive-muted">Execution is available on the published page after saving.</p>:null}{error?<p className="interactive-error-copy">{error}</p>:null}{result?<div className={result.exitCode===0?'interactive-learn-feedback is-correct':'interactive-learn-feedback is-incorrect'}><strong>Exit {result.exitCode}</strong>{result.stdout?<pre>{result.stdout}</pre>:null}{result.stderr?<pre>{result.stderr}</pre>:null}</div>:null}</section>;
}

function Checkpoint({block,kind,slug,authenticated,onAuthRequired,interactive,runtime,blockState}:{block:LearnBlock;kind:CmsInteractiveKind;slug:string;authenticated:boolean;onAuthRequired:(blockId?:string)=>void;interactive:boolean;runtime:CmsInteractiveRuntime;blockState?:CmsInteractiveState['blocks'][string]}){const options=array(block.data,'options').map(String);const multiple=String(block.data.kind)==='multiple';const [selected,setSelected]=React.useState<number[]>([]);const [result,setResult]=React.useState<{correct:boolean;explanation?:string}|undefined>(()=>blockState?.status==='passed'?{correct:true,explanation:'Completed previously.'}:undefined);const [busy,setBusy]=React.useState(false);const toggle=(index:number)=>setSelected(current=>multiple?(current.includes(index)?current.filter(v=>v!==index):[...current,index]):[index]);const submit=async()=>{if(!authenticated){onAuthRequired(block.id);return;}if(!selected.length)return;setBusy(true);try{setResult(await runtime.gradeCheckpoint(block.id,multiple?selected:selected[0]));}catch(reason){setResult({correct:false,explanation:reason instanceof Error?reason.message:String(reason)});}finally{setBusy(false)}};return <section id={`block-${block.id}`} className="interactive-learn-checkpoint"><span className="interactive-learn-block-label">Checkpoint</span><h3>{text(block.data,'question')}</h3><div className="interactive-learn-checkpoint-options">{options.map((option,index)=><label key={`${index}-${option}`}><input type={multiple?'checkbox':'radio'} checked={selected.includes(index)} onChange={()=>toggle(index)}/><span>{option}</span></label>)}</div>{interactive?(authenticated?<button type="button" className="interactive-button interactive-button-primary" disabled={!selected.length||busy} onClick={()=>void submit()}>{busy?'Checking…':'Check answer'}</button>:<CmsAuthAction onAuthRequired={()=>onAuthRequired(block.id)}>Check answer</CmsAuthAction>):null}{result?<div className={result.correct?'interactive-learn-feedback is-correct':'interactive-learn-feedback is-incorrect'}><strong>{result.correct?'Correct':'Try again'}</strong>{result.explanation?<p>{result.explanation}</p>:null}</div>:null}</section>;}

function Solution({block,kind,slug,authenticated,onAuthRequired,interactive,runtime,blockState}:{block:LearnBlock;kind:CmsInteractiveKind;slug:string;authenticated:boolean;onAuthRequired:(blockId?:string)=>void;interactive:boolean;runtime:CmsInteractiveRuntime;blockState?:CmsInteractiveState['blocks'][string]}){const [value,setValue]=React.useState<{title:string;content:string}>();const [error,setError]=React.useState('');const reveal=async()=>{if(!authenticated){onAuthRequired(block.id);return;}try{setValue(await runtime.getSolution(block.id));}catch(reason){setError(reason instanceof Error?reason.message:String(reason));}};return <section id={`block-${block.id}`} className="interactive-learn-solution">{interactive?(authenticated?<button type="button" className="interactive-button interactive-button-secondary" onClick={()=>void reveal()}><Eye className="size-4"/> Reveal solution</button>:<CmsAuthAction onAuthRequired={()=>onAuthRequired(block.id)}><Eye className="size-4"/> Reveal solution</CmsAuthAction>):<p className="interactive-muted">Protected solution is available on the published page according to its reveal policy.</p>}{value?<div><h3>{value.title}</h3><pre>{value.content}</pre></div>:null}{error?<p className="interactive-error-copy">{error}</p>:null}</section>;}

function CodeExercise({block,kind,slug,authenticated,onAuthRequired,interactive,runtime,blockState}:{block:LearnBlock;kind:CmsInteractiveKind;slug:string;authenticated:boolean;onAuthRequired:(blockId?:string)=>void;interactive:boolean;runtime:CmsInteractiveRuntime;blockState?:CmsInteractiveState['blocks'][string]}){const starter=(block.data.starter||{files:{}}) as LearnStarter;const initialFiles=React.useMemo(()=>({...starter.files}),[starter]);const paths=Object.keys(initialFiles);const defaultPath=String(block.data.entryFile||starter.entryFile||paths[0]||'');const [files,setFiles]=React.useState<Record<string,string>>(initialFiles);const [activePath,setActivePath]=React.useState(defaultPath);const [stdin,setStdin]=React.useState(text(block.data,'exampleStdin'));const [busy,setBusy]=React.useState<'run'|'check'|null>(null);const [result,setResult]=React.useState<{passed?:boolean;exitCode:number;stdout:string;stderr:string;visibleTests?:Array<{index:number;label:string;passed:boolean}>;hiddenTests?:{passed:number;total:number}}|undefined>(()=>blockState?.status==='passed'?{passed:true,exitCode:0,stdout:'',stderr:''}:undefined);const [error,setError]=React.useState('');React.useEffect(()=>{setFiles(initialFiles);setActivePath(defaultPath);setStdin(text(block.data,'exampleStdin'));setResult(undefined);setError('')},[initialFiles,defaultPath,block.data.exampleStdin]);const ensure=()=>{if(authenticated)return true;onAuthRequired(block.id);return false;};const run=async()=>{if(!ensure())return;setBusy('run');setError('');try{setResult(await runtime.runExercise(block.id,files,activePath||defaultPath,stdin));}catch(reason){setError(reason instanceof Error?reason.message:String(reason));}finally{setBusy(null)}};const check=async()=>{if(!ensure())return;setBusy('check');setError('');try{setResult(await runtime.checkExercise(block.id,files,activePath||defaultPath));}catch(reason){setError(reason instanceof Error?reason.message:String(reason));}finally{setBusy(null)}};const reset=()=>{setFiles(initialFiles);setActivePath(defaultPath);setStdin(text(block.data,'exampleStdin'));setResult(undefined);setError('')};return <section id={`block-${block.id}`} className="interactive-learn-exercise"><div><span className="interactive-learn-block-label">Interactive exercise</span><h3>{text(block.data,'title')||'Code exercise'}</h3><p>{text(block.data,'instructions')}</p></div>{paths.length?<div className="interactive-learn-exercise-editor"><header>{paths.length>1?<select value={activePath} onChange={event=>setActivePath(event.currentTarget.value)}>{paths.map(path=><option key={path} value={path}>{path}</option>)}</select>:<strong>{activePath}</strong>}<button type="button" onClick={reset}><RotateCcw className="size-4"/> Reset</button></header><textarea spellCheck={false} value={files[activePath]||''} onChange={event=>{const value=event.currentTarget.value;setFiles(current=>({...current,[activePath]:value}));}}/></div>:null}<label className="interactive-learn-exercise-stdin"><span>Input for Run</span><textarea value={stdin} onChange={event=>setStdin(event.currentTarget.value)}/></label>{interactive?<div className="interactive-learn-exercise-actions"><button type="button" className="interactive-button interactive-button-secondary" disabled={Boolean(busy)||!paths.length} onClick={()=>void run()}><Play className="size-4"/>{busy==='run'?'Running…':'Run'}</button><button type="button" className="interactive-button interactive-button-primary" disabled={Boolean(busy)||!paths.length} onClick={()=>void check()}><Check className="size-4"/>{busy==='check'?'Checking…':'Check'}</button></div>:<p className="interactive-muted">Run and Check activate on the published page.</p>}{error?<p className="interactive-error-copy">{error}</p>:null}{result?<div className={result.passed===false||result.exitCode!==0?'interactive-learn-feedback is-incorrect':'interactive-learn-feedback is-correct'}><strong>{result.passed===false?'Checks need attention':result.passed?'All checks passed':`Run result · exit ${result.exitCode}`}</strong>{result.stdout?<pre>{result.stdout}</pre>:null}{result.stderr?<pre>{result.stderr}</pre>:null}{result.hiddenTests?.total?<p>Hidden checks: {result.hiddenTests.passed}/{result.hiddenTests.total}</p>:null}</div>:null}</section>;}

function Terminal({block,authenticated,onAuthRequired,interactive}:{block:LearnBlock;authenticated:boolean;onAuthRequired:(blockId?:string)=>void;interactive:boolean}){const [open,setOpen]=React.useState(true);const [started,setStarted]=React.useState(false);const starter=(block.data.starter||{files:{}}) as LearnStarter;const directory=text(block.data,'workingDirectory')||starter.cwd||'';return <section id={`block-${block.id}`} className="interactive-learn-terminal"><div className="interactive-learn-terminal-head"><div><span className="interactive-learn-block-label"><SquareTerminal className="size-4"/> Terminal</span><h3>{text(block.data,'title')||'Terminal'}</h3><p>{text(block.data,'instructions')}</p></div></div>{!interactive?<p className="interactive-muted">The terminal activates on the published page.</p>:!authenticated?<CmsAuthAction onAuthRequired={()=>onAuthRequired(block.id)}>Sign in to start terminal</CmsAuthAction>:!started?<button type="button" className="interactive-button interactive-button-primary" onClick={()=>setStarted(true)}><SquareTerminal className="size-4"/> Start terminal</button>:<LinuxTerminalPro open={open} onOpenChange={setOpen} context="homepage" embedded initialFiles={starter.files||{}} initialDirectory={directory||undefined} initialCommand={text(block.data,'setupCommand')||undefined}/>}</section>;}

function TerminalTask({block,kind,slug,authenticated,onAuthRequired,interactive,runtime,blockState}:{block:LearnBlock;kind:CmsInteractiveKind;slug:string;authenticated:boolean;onAuthRequired:(blockId?:string)=>void;interactive:boolean;runtime:CmsInteractiveRuntime;blockState?:CmsInteractiveState['blocks'][string]}){const [open,setOpen]=React.useState(true);const [attempt,setAttempt]=React.useState<{id:string;attemptNumber:number;projectId:string;generation:number}>();const [busy,setBusy]=React.useState<'verify'|'reset'|''>('');const [result,setResult]=React.useState<{passed:boolean;message?:string;checks?:Array<{label:string;passed:boolean}>}|undefined>(()=>blockState?.status==='passed'?{passed:true,message:'Completed previously.'}:undefined);const [error,setError]=React.useState('');const sessionFactory=React.useCallback(async()=>{if(!authenticated){onAuthRequired(block.id);throw new Error('authentication_required');}const created=await runtime.startTerminalTask(block.id);setAttempt(created.attempt);return created.terminalSession as never;},[authenticated,block.id,kind,onAuthRequired,runtime,slug]);const verify=async()=>{if(!attempt)return;setBusy('verify');try{setResult(await runtime.verifyTerminalTask(block.id,attempt.id));}catch(reason){setError(reason instanceof Error?reason.message:String(reason));}finally{setBusy('')}};const reset=async()=>{if(!attempt)return;setBusy('reset');try{await runtime.resetTerminalTask(block.id,attempt.id);setResult({passed:false,message:'Environment reset to the task starter state.'});}catch(reason){setError(reason instanceof Error?reason.message:String(reason));}finally{setBusy('')}};const directory=text(block.data,'workingDirectory');return <section id={`block-${block.id}`} className="interactive-learn-terminal interactive-learn-terminal-task"><div className="interactive-learn-terminal-head"><div><span className="interactive-learn-block-label"><SquareTerminal className="size-4"/> Terminal Task</span><h3>{text(block.data,'title')||'Terminal task'}</h3><p>{text(block.data,'instructions')}</p>{attempt?<small>Attempt {attempt.attemptNumber}</small>:null}</div></div>{!interactive?<p className="interactive-muted">The isolated terminal task activates on the published page.</p>:!authenticated?<CmsAuthAction onAuthRequired={()=>onAuthRequired(block.id)}>Sign in to start terminal task</CmsAuthAction>:<><LinuxTerminalPro open={open} onOpenChange={setOpen} context="homepage" embedded sessionFactory={sessionFactory} initialDirectory={directory&&directory!=='.'?directory:undefined}/><div className="interactive-learn-terminal-task-actions"><button type="button" className="interactive-button interactive-button-primary" disabled={!attempt||Boolean(busy)} onClick={()=>void verify()}><Check className="size-4"/>{busy==='verify'?'Verifying…':'Verify Task'}</button>{String(block.data.resetPolicy)!=='disabled'?<button type="button" className="interactive-button interactive-button-secondary" disabled={!attempt||Boolean(busy)} onClick={()=>void reset()}><RotateCcw className="size-4"/>{busy==='reset'?'Resetting…':'Reset environment'}</button>:null}</div></>}{result?<div className={result.passed?'interactive-learn-feedback is-correct':'interactive-learn-feedback is-incorrect'}><strong>{result.passed?'Task complete':result.message||'Task not complete yet.'}</strong>{result.checks?.length?<ul>{result.checks.map((check,index)=><li key={index}>{check.passed?'✓':'✕'} {check.label}</li>)}</ul>:null}</div>:null}{error?<p className="interactive-error-copy">{error}</p>:null}</section>;}

function NestedBlocks({blocks}:{blocks:unknown[]}){return <div className="interactive-learn-nested-blocks">{blocks.slice(0,100).map((raw,index)=>{const block=(raw&&typeof raw==='object'&&!Array.isArray(raw)?raw:{}) as {id?:string;type?:string;data?:Record<string,unknown>};const d=block.data||{};const key=block.id||String(index);switch(block.type){case'paragraph':return <p key={key}><RichText html={text(d,'text')}/></p>;case'header':return React.createElement(`h${Math.min(4,Math.max(2,number(d,'level')||3))}`,{key},<RichText html={text(d,'text')}/>);case'quote':return <blockquote key={key}><RichText html={text(d,'text')}/></blockquote>;case'callout':return <aside key={key} className={`interactive-learn-callout tone-${String(d.tone||'info')}`}><Lightbulb className="size-5"/><div><RichText html={text(d,'text')}/></div></aside>;case'code':return <pre key={key}><code>{text(d,'code')}</code></pre>;case'list':return <NestedList key={key} items={array(d,'items')} ordered={String(d.style)==='ordered'}/>;case'image':{const src=mediaUrl(d);return src?<figure key={key}><img src={src} alt={text(d,'alt')}/></figure>:null;}default:return null;}})}</div>;}
function Tabs({data,blockId}:{data:Record<string,unknown>;blockId:string}){const tabs=array(data,'tabs').map((raw,index)=>{const tab=(raw||{}) as {id?:string;title?:string;blocks?:unknown[]};return{id:tab.id||`tab-${index}`,title:tab.title||`Tab ${index+1}`,blocks:Array.isArray(tab.blocks)?tab.blocks:[]}});const [active,setActive]=React.useState(0);if(!tabs.length)return null;const select=(index:number)=>setActive((index+tabs.length)%tabs.length);return <section className="interactive-learn-tabs"><div className="interactive-learn-tabs-nav" role="tablist">{tabs.map((tab,index)=><button key={tab.id} id={`tab-${blockId}-${tab.id}`} type="button" role="tab" aria-controls={`panel-${blockId}-${tab.id}`} aria-selected={active===index} tabIndex={active===index?0:-1} className={active===index?'is-active':''} onClick={()=>select(index)} onKeyDown={event=>{if(event.key==='ArrowRight'){event.preventDefault();select(active+1)}else if(event.key==='ArrowLeft'){event.preventDefault();select(active-1)}else if(event.key==='Home'){event.preventDefault();select(0)}else if(event.key==='End'){event.preventDefault();select(tabs.length-1)}}}>{tab.title}</button>)}</div><div id={`panel-${blockId}-${tabs[active]?.id}`} role="tabpanel" aria-labelledby={`tab-${blockId}-${tabs[active]?.id}`} className="interactive-learn-tabs-panel"><NestedBlocks blocks={tabs[active]?.blocks||[]}/></div></section>;}
function Accordion({data}:{data:Record<string,unknown>}){return <div className="interactive-learn-accordion">{array(data,'items').map((raw,index)=>{const item=(raw||{}) as {id?:string;title?:string;blocks?:unknown[]};return <details key={item.id||index}><summary>{item.title||`Section ${index+1}`}</summary><NestedBlocks blocks={Array.isArray(item.blocks)?item.blocks:[]}/></details>})}</div>;}

export function CmsInteractiveContent({document,kind,slug,authenticated,onAuthRequired,interactive=true,headingIds=false,runtime:runtimeOverride,state}:{document:InteractiveContentDocument;kind:CmsInteractiveKind;slug:string;authenticated:boolean;onAuthRequired:(blockId?:string)=>void;interactive?:boolean;headingIds?:boolean;runtime?:CmsInteractiveRuntime;state?:CmsInteractiveState}){const toc=React.useMemo(()=>interactiveContentToc(document),[document]);const runtime=React.useMemo(()=>runtimeOverride||defaultRuntime(kind,slug),[kind,runtimeOverride,slug]);let headingIndex=0;return <div className="interactive-learn-renderer interactive-cms-interactive-renderer">{(document.blocks||[]).map(block=>{const d=block.data;switch(block.type){case'paragraph':return <p key={block.id}><RichText html={text(d,'text')}/></p>;case'header':{const level=Math.min(4,Math.max(2,number(d,'level')||2));const entry=level<=3?toc[headingIndex++]:undefined;return React.createElement(`h${level}`,{key:block.id,...(headingIds&&entry?{id:entry.id}:{})},<RichText html={text(d,'text')}/>);}case'list':return <div key={block.id} className="interactive-learn-list"><NestedList items={array(d,'items')} ordered={String(d.style)==='ordered'}/></div>;case'checklist':return <div key={block.id} className="interactive-learn-checklist">{array(d,'items').map((raw,index)=>{const item=(raw||{}) as {text?:string;checked?:boolean};return <label key={index}><input type="checkbox" checked={Boolean(item.checked)} readOnly/><RichText html={String(item.text||'')}/></label>})}</div>;case'quote':return <blockquote key={block.id}><RichText html={text(d,'text')}/>{text(d,'caption')?<cite>{text(d,'caption')}</cite>:null}</blockquote>;case'delimiter':return <hr key={block.id}/>;case'table':return <div key={block.id} className="interactive-learn-table-wrap"><table><tbody>{array(d,'content').map((raw,rowIndex)=>{const row=Array.isArray(raw)?raw:[];return <tr key={rowIndex}>{row.map((cell,columnIndex)=>d.withHeadings!==false&&rowIndex===0?<th key={columnIndex} scope="col"><RichText html={String(cell??'')}/></th>:<td key={columnIndex}><RichText html={String(cell??'')}/></td>)}</tr>})}</tbody></table></div>;case'callout':return <aside key={block.id} className={`interactive-learn-callout tone-${String(d.tone||'info')}`}><Lightbulb className="size-5"/><div>{text(d,'title')?<strong>{text(d,'title')}</strong>:null}<p><RichText html={text(d,'text')}/></p></div></aside>;case'image':{const src=mediaUrl(d);return src?<figure key={block.id} className={`interactive-learn-image align-${text(d,'alignment')||'center'}`}><img style={{width:`${Math.min(100,Math.max(25,number(d,'widthPercent')||100))}%`}} src={src} alt={text(d,'alt')}/>{text(d,'caption')?<figcaption>{text(d,'caption')}</figcaption>:null}</figure>:null;}case'gallery':{const urls=[...array(d,'mediaUrls').map(String),...array(d,'mediaIds').map(id=>`/api/learn/media/${Number(id)}`)].filter(Boolean);return <div key={block.id} className="interactive-learn-gallery">{urls.map((url,index)=><img key={`${url}-${index}`} src={url} alt={String(array(d,'alts')[index]||d.alt||`Gallery image ${index+1}`)}/>)}</div>;}case'video':return <div key={block.id} className="interactive-learn-video"><LearnVideoPlayer provider={String(d.source||'upload') as 'upload'|'youtube'|'wistia'|'direct'} mediaId={number(d,'mediaId')||undefined} mediaUrl={text(d,'mediaUrl')||undefined} externalId={text(d,'externalId')||undefined} directUrl={text(d,'directUrl')||undefined} title={text(d,'title')||'Video'} posterUrl={mediaUrl(d,'posterMediaId','posterMediaUrl')||undefined} captionUrl={mediaUrl(d,'captionMediaId','captionMediaUrl')||undefined}/></div>;case'audio':{const src=mediaUrl(d);return src?<audio key={block.id} controls src={src}/>:null;}case'file':{const src=mediaUrl(d);return src?<a key={block.id} className="interactive-learn-file" href={src} target="_blank" rel="noreferrer"><FileDown className="size-5"/><span><strong>{text(d,'label')||text(d,'filename')||'Download file'}</strong>{text(d,'description')?<small>{text(d,'description')}</small>:null}</span></a>:null;}case'code':return <RunnableCode key={block.id} block={block} kind={kind} slug={slug} authenticated={authenticated} onAuthRequired={onAuthRequired} interactive={interactive} runtime={runtime} blockState={state?.blocks?.[block.id]}/>;case'terminal':return <Terminal key={block.id} block={block} authenticated={authenticated} onAuthRequired={onAuthRequired} interactive={interactive}/>;case'terminalTask':return <TerminalTask key={block.id} block={block} kind={kind} slug={slug} authenticated={authenticated} onAuthRequired={onAuthRequired} interactive={interactive} runtime={runtime} blockState={state?.blocks?.[block.id]}/>;case'codeExercise':return <CodeExercise key={block.id} block={block} kind={kind} slug={slug} authenticated={authenticated} onAuthRequired={onAuthRequired} interactive={interactive} runtime={runtime} blockState={state?.blocks?.[block.id]}/>;case'checkpoint':return <Checkpoint key={block.id} block={block} kind={kind} slug={slug} authenticated={authenticated} onAuthRequired={onAuthRequired} interactive={interactive} runtime={runtime} blockState={state?.blocks?.[block.id]}/>;case'solution':return <Solution key={block.id} block={block} kind={kind} slug={slug} authenticated={authenticated} onAuthRequired={onAuthRequired} interactive={interactive} runtime={runtime} blockState={state?.blocks?.[block.id]}/>;case'tabs':return <Tabs key={block.id} data={d} blockId={block.id}/>;case'accordion':return <Accordion key={block.id} data={d}/>;case'legacyImport':return <section key={block.id} className="interactive-learn-callout tone-warning"><strong>Legacy content preserved</strong><p>This block needs administrator review before it can be converted further.</p></section>;default:return null;}})}</div>;}
