'use client';
import { useEffect, useRef, useState } from 'react';
import { Play, Pause, SkipBack, SkipForward, RotateCcw, Plus, Minus, ArrowUpRight, X, Info, MoveUpRight } from 'lucide-react';
import { Slider } from '@/components/ui/slider';
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@/components/ui/select';
import { Dialog, DialogTrigger, DialogContent, DialogTitle, DialogDescription } from '@/components/ui/dialog';
import { CONFIG, FIRING_ORDER, cylinderState, mod, tourState } from '@/lib/mechanics.mjs';
import { createEngineScene } from '@/lib/engine-scene.mjs';

const TEXT:Record<string,string>={Power:'Expanding gases push the piston down. The rod turns that force into rotation.',Exhaust:'The piston rises. The exhaust valve opens to let the spent gases leave.',Intake:'The piston descends. The intake valve opens to admit a fresh charge.',Compression:'Both valves close. The rising piston compresses the charge for ignition.'};
const CHAPTERS=['Meet the complete engine','Open the cylinder banks','One cylinder. Four strokes.','Separate the housings','Everything, working together'];
const INITIAL={angle:35,selected:1,view:'section',playing:true,speed:.5,tour:false,time:0};
function Diagram({angle,selected}:{angle:number,selected:number}){
 const s=cylinderState(angle,selected);const top=137-s.s*27-8;const pinX=66+(s.pin[0]*Math.cos(s.beta)-s.pin[1]*Math.sin(s.beta))*27,pinY=137-(s.pin[0]*Math.sin(s.beta)+s.pin[1]*Math.cos(s.beta))*27;
 const graphic=(<g><path d="M39 29V112 M94 29V112" fill="none" stroke="#aeb4a6" strokeWidth="2"/>
  <path d="M40 27H94" stroke="#aeb4a6" strokeWidth="2"/>
  <rect x="41" y="29" width="51" height={Math.max(1,top-29)} fill={s.stroke==='Power'?'#b4432b':s.stroke==='Intake'?'#c4cbb9':'#d9d8cf'} opacity={s.stroke==='Power'? .15+.12*(1-s.phase/180):.42}/>
  <path d={`M50 17v${12+s.intakeLift*25}m-6 0h12 M83 17v${12+s.exhaustLift*25}m-6 0h12`} stroke="#9e7651" strokeWidth="2"/>
  <circle cx="66" cy="137" r="15" fill="none" stroke="#bfc4b7" strokeWidth="1"/>
  <path d={`M66 137L${pinX} ${pinY}L66 ${top+8}`} fill="none" stroke="#af825b" strokeWidth="5" strokeLinejoin="round"/>
  <rect x="41" y={top} width="51" height="16" rx="2" fill="#6c7769"/>
  <path d={`M41 ${top+4}h51`} stroke="#dde1d7" strokeWidth="1"/>
  <circle cx={pinX} cy={pinY} r="4" fill="#f4f2ed" stroke="#a27350" strokeWidth="2"/>
  <circle cx="66" cy="137" r="3" fill="#77806f"/>
  </g>);
 return <><svg className="cycle-diagram" viewBox="0 0 260 170" role="img" aria-label={`Cylinder ${selected}: ${s.stroke}. Intake ${s.intakeLift>0?'open':'closed'}, exhaust ${s.exhaustLift>0?'open':'closed'}.`}>
  {graphic}<path className="diagram-leader" d="M115 46h14 M115 81h14 M115 137h14" stroke="#bfc4b7"/>
  <text x="138" y="44" fill="#727b68" fontSize="10" letterSpacing="1">VALVES</text><text x="138" y="59" fill="#353f32" fontSize="11">{s.intakeLift>0?'Intake open':s.exhaustLift>0?'Exhaust open':'Both closed'}</text>
  <text x="138" y="87" fill="#727b68" fontSize="10" letterSpacing="1">PISTON</text><text x="138" y="102" fill="#353f32" fontSize="11">{Math.round(s.travel/(CONFIG.radius*2)*100)}% from top</text>
  <text x="138" y="138" fill="#727b68" fontSize="10" letterSpacing="1">CRANKSHAFT</text><text x="138" y="153" fill="#353f32" fontSize="11">{Math.floor(mod(angle,360))}° / revolution</text>
 </svg><svg className="cycle-diagram-mobile" viewBox="24 8 92 151" role="img" aria-label={`Cylinder ${selected}: ${s.stroke}.`}>{graphic}</svg></>
}
export default function Home(){
 const host=useRef<HTMLDivElement>(null),engine=useRef<any>(null),state=useRef({...INITIAL}),capture=useRef(false);
 const [ui,setUi]=useState({...INITIAL}),[error,setError]=useState(''),[ready,setReady]=useState(false);
 const publish=()=>setUi({...state.current});
 const change=(patch:any)=>{Object.assign(state.current,patch);publish();};
 const manual=(patch:any={})=>change({tour:false,...patch});
 const choose=(selected:number)=>manual({selected});
 useEffect(()=>{
   capture.current=new URLSearchParams(location.search).has('capture');
   state.current.playing=!capture.current&&!matchMedia('(prefers-reduced-motion: reduce)').matches;
   let raf=0,last=performance.now(),uiTime=0,viewCut=1,viewExplode=0;
   try{engine.current=createEngineScene(host.current,choose,()=>manual());}catch(e:any){setError(`The 3D view could not start. Enable WebGL 2 in your browser. ${e.message}`);return;}
   const apply=()=>{
     const s=state.current;let sceneState:any;
     if(s.tour){const t=tourState(s.time);sceneState={...t,tour:true,selected:s.selected};s.angle=t.angle;s.view=t.view;viewCut=t.cut;viewExplode=t.explode;}
     else sceneState={angle:s.angle,selected:s.selected,cut:viewCut,explode:viewExplode,tour:false};
     engine.current.update(sceneState);
   };
   const loop=(now:number)=>{const dt=Math.min((now-last)/1000,.08);last=now;const s=state.current;
     if(!capture.current){if(s.tour&&s.playing){s.time=Math.min(18,s.time+dt);if(s.time>=18){s.tour=false;s.view='assembled';s.playing=false;}}else if(s.playing)s.angle=mod(s.angle+dt*120*s.speed,720);
       const targetCut=s.view==='assembled'?0:1,targetEx=s.view==='exploded'?1:0;viewCut+=(targetCut-viewCut)*Math.min(1,dt*5);viewExplode+=(targetEx-viewExplode)*Math.min(1,dt*5);}
     apply();if(now-uiTime>70){publish();uiTime=now;}raf=requestAnimationFrame(loop);
   };
   const api={
     getState:()=>({...state.current,cylinder:cylinderState(state.current.angle,state.current.selected),scene:engine.current.inspect()}),
     setState:(patch:any)=>{if(patch.angle!==undefined&&(!Number.isFinite(patch.angle)||patch.angle<0||patch.angle>720))throw Error('Angle must be 0–720');if(patch.selected!==undefined&&(!Number.isInteger(patch.selected)||patch.selected<1||patch.selected>8))throw Error('Cylinder must be 1–8');if(patch.view!==undefined&&!['section','assembled','exploded'].includes(patch.view))throw Error('Unknown view');Object.assign(state.current,patch);viewCut=state.current.view==='assembled'?0:1;viewExplode=state.current.view==='exploded'?1:0;apply();publish();return api.getState();},
     seekTour:(time:number)=>{capture.current=true;Object.assign(state.current,{tour:true,playing:false,time,selected:1});apply();publish();return api.getState();},
     exportGLTF:()=>engine.current.exportGLTF(), reset:()=>engine.current.reset(), setCapture:(value:boolean)=>{capture.current=value;},
   };
   (window as any).engineExhibit=api;
   const controller=new AbortController();const modelContext=(document as any).modelContext;
   if(modelContext?.registerTool){Promise.resolve(modelContext.registerTool({name:'inspect_v8_cylinder',title:'Inspect a V8 cylinder',description:'Pause the exhibit at a chosen crank angle and select a cylinder.',inputSchema:{type:'object',properties:{angle:{type:'number',minimum:0,maximum:720},cylinder:{type:'integer',minimum:1,maximum:8}},required:['angle','cylinder'],additionalProperties:false},execute:(input:any)=>api.setState({angle:input.angle,selected:input.cylinder,playing:false,tour:false,view:'section'})},{signal:controller.signal})).catch(()=>{});}
   apply();publish();setReady(true);raf=requestAnimationFrame(loop);
   return()=>{cancelAnimationFrame(raf);controller.abort();engine.current.dispose();delete (window as any).engineExhibit;};
 },[]);
 const s=cylinderState(ui.angle,ui.selected),phase=Math.floor(s.phase),cycleNumber=Math.floor(ui.angle);
 const startTour=()=>{engine.current.reset();change({tour:true,time:0,playing:true,selected:1});capture.current=false;};
 return <main className={`exhibit ${ui.tour?'tour-mode':''}`}>
  <header className="masthead"><div className="brand"><span className="brand-mark">im</span>MECHANICAL STUDIES</div><span className="mast-note">An exploration of motion</span><Dialog><DialogTrigger className="text-button"><Info size={15}/>About this model</DialogTrigger><DialogContent className="info-dialog"><DialogTitle>A mechanism, made visible.</DialogTitle><DialogDescription>This original exhibit uses the layout of a traditional Chevrolet small-block V8 to explain linked motion.</DialogDescription><h3>One consistent configuration</h3><p>90° banks · cross-plane crankshaft · one cam in the block · two overhead valves per cylinder. Looking forward from the flywheel, the left bank is 1–3–5–7 and the right is 2–4–6–8, front to rear. The front pulley faces you in the reset view.</p><h3>Two revolutions. Eight firings.</h3><p>The order is 1–8–4–3–6–5–7–2, spaced 90° apart. At 0°, cylinder 1 is at the start of its power stroke. The cam turns once for every two crankshaft turns. Every piston, rod and valve is derived from this angle.</p><h3>What is simplified</h3><ul><li>Normalized dimensions, ideal rigid links, no friction or structural simulation.</li><li>Valve timing uses smooth ideal 180° windows. Real engines open valves earlier and close them later. The rocker geometry reverses motion; tappets and lobe outlines are schematic, not contact-solved cam design.</li><li>The chain is a static envelope. Small fasteners, coolant passages, combustion details and accessories are omitted.</li><li>In exploded view, housings separate while the connected mechanism stays together. Housings become translucent for inspection.</li><li>Red identifies your selected piston. Chamber tint in the linked diagram only illustrates the stroke. It is not pressure or temperature data.</li></ul><h3>Primary references</h3><p><a href="https://www.gm.com/content/dam/company/no_search/heritage-archive-docs/vehicle-information-kits/chevrolet/1961-Chevrolet-Corvette.pdf" target="_blank" rel="noreferrer">GM · 1961 Corvette specifications</a><br/><a href="https://www.grc.nasa.gov/WWW/K-12/BGP/engopt.html" target="_blank" rel="noreferrer">NASA · four-stroke engine cycle</a></p><p>Procedural original geometry. This visual exhibit is not engineering validation or a reconstruction of a creator’s private prompt.</p></DialogContent></Dialog></header>
  <div className="title-row"><div><p className="eyebrow">01 / The cross-plane V8</p><h1>Inside the <em>machine.</em></h1></div><div className="edition"><div><span>CONFIGURATION</span><b>90° V8 / OHV</b></div><div><span>ONE CYCLE</span><b>720° of rotation</b></div></div></div>
  <div className="main-grid"><section className="stage" aria-label="Engine inspection"><div ref={host} className="engine-host"/>{error&&<p className="failure" role="alert">{error}</p>}{ready&&<span className="ready" data-testid="engine-ready">3D engine ready</span>}
    {ui.tour&&<div className="tour-caption"><b>0{tourState(ui.time).stage+1} / 05</b>{CHAPTERS[tourState(ui.time).stage]}</div>}
    <div className="stage-note"><b>{ui.view==='assembled'?'Complete engine':ui.view==='exploded'?'Housings separated':'Section through both banks'}</b>{ui.view==='exploded'?'Linked mechanism held together':'Drag to orbit · scroll to zoom'}</div>
    <div className="stage-tools"><button className="icon-button" aria-label="Zoom in" onClick={()=>{manual();engine.current.zoom(.9);}}><Plus size={15}/></button><button className="icon-button" aria-label="Zoom out" onClick={()=>{manual();engine.current.zoom(1.1);}}><Minus size={15}/></button><button className="icon-button" aria-label="Reset camera" onClick={()=>{manual();engine.current.reset();}}><RotateCcw size={14}/></button></div>
    <Tabs className="view-tabs" value={ui.view} onValueChange={view=>manual({view})}><TabsList aria-label="Inspection view"><TabsTrigger value="assembled">Assembled</TabsTrigger><TabsTrigger value="section">Section</TabsTrigger><TabsTrigger value="exploded">Exploded</TabsTrigger></TabsList></Tabs>
   </section>
   <aside className="inspector" aria-label="Selected cylinder"><p className="eyebrow">Follow cylinder {ui.selected}</p><div className="cylinder-chooser" role="group" aria-label="Cylinder selection">{Array.from({length:8},(_,i)=>i+1).map(n=><button key={n} className={n===ui.selected?'active':''} aria-label={`Follow cylinder ${n}`} aria-pressed={n===ui.selected} onClick={()=>choose(n)}>{n}</button>)}</div><div className="stroke-heading"><h2>{s.stroke}</h2><span className="stroke-number">0{s.strokeIndex+1} / 04</span></div><p className="stroke-copy">{TEXT[s.stroke]}<span className="mobile-valve">{s.intakeLift>0?'Intake valve open':s.exhaustLift>0?'Exhaust valve open':'Both valves closed'}</span></p><Diagram angle={ui.angle} selected={ui.selected}/><div className="stroke-grid">{['Power','Exhaust','Intake','Compress'].map((x,i)=><span className={s.strokeIndex===i?'on':''} key={x}>{x}</span>)}</div><button className="tour-button" onClick={ui.tour?()=>manual({playing:false}):startTour}><span>{ui.tour?'Leave guided tour':'Take a guided look'}<small> / {ui.tour?`${ui.time.toFixed(0)}s`:'18 sec'}</small></span>{ui.tour?<X size={16}/>:<ArrowUpRight size={18}/>}</button>{ui.tour&&<button className="manual-link" onClick={()=>manual({playing:false})}>Return to manual control</button>}</aside>
  </div>
  <section className="transport" aria-label="Playback controls"><div className="playback"><button className="step-button" aria-label="Step back 15 degrees" onClick={()=>manual({playing:false,angle:mod(ui.angle-15,720)})}><SkipBack size={15}/></button><button className="play-button" aria-label={ui.playing?'Pause':'Play'} onClick={()=>change({playing:!ui.playing})}>{ui.playing?<Pause size={18}/>:<Play size={18} fill="currentColor"/>}</button><button className="step-button" aria-label="Step forward 15 degrees" onClick={()=>manual({playing:false,angle:mod(ui.angle+15,720)})}><SkipForward size={15}/></button></div><div className="timeline"><div className="timeline-head"><label id="cycle-label">Four-stroke cycle</label><span className="angle-label">{String(cycleNumber).padStart(3,'0')}° <span>/ 720°</span></span></div><Slider aria-labelledby="cycle-label" aria-label="Crank angle" value={[ui.angle]} min={0} max={720} step={1} onValueChange={value=>manual({angle:Array.isArray(value)?value[0]:value,playing:false})}/><div className="timeline-ticks"><span>0° · ignition 1</span><span>180°</span><span>360°</span><span>540°</span><span>720°</span></div></div><div className="speed"><label id="speed-label">Playback speed</label><Select value={String(ui.speed)} onValueChange={value=>manual({speed:Number(value)})}><SelectTrigger aria-labelledby="speed-label"><SelectValue>{ui.speed}× {ui.speed===.25?'very slow':ui.speed===.5?'slow motion':ui.speed===1?'study pace':'fast'}</SelectValue></SelectTrigger><SelectContent>{[.25,.5,1,2].map(n=><SelectItem value={String(n)} key={n}>{n}× {n===.25?'very slow':n===.5?'slow motion':n===1?'study pace':'fast'}</SelectItem>)}</SelectContent></Select></div></section>
  <footer className="bottomline"><span>FIRING ORDER <strong>1 — 8 — 4 — 3 — 6 — 5 — 7 — 2</strong></span><span>CRANK : CAM <strong>2 : 1</strong></span><span>Stroke tint is illustrative · no thermodynamic simulation</span></footer>
 </main>
}
