function PField({ label, children }) {
  return (
    <div style={{ marginBottom:12 }}>
      <div style={{ fontFamily:"'Archivo',sans-serif", fontWeight:700, fontSize:9, letterSpacing:'0.16em', textTransform:'uppercase', color:PC.muted, marginBottom:5 }}>{label}</div>
      {children}
    </div>
  );
}

const iStyle = {
  width:'100%', padding:'7px 10px', background:PC.bg, border:`1px solid ${PC.line}`,
  borderRadius:4, fontFamily:"'Archivo',sans-serif", fontSize:13, color:PC.ink,
  outline:'none', boxSizing:'border-box',
};
const monoStyle = { ...iStyle, fontFamily:"'Space Mono',monospace" };

function ZoneSelector({ value, onChange }) {
  return (
    <div style={{ display:'flex', gap:4 }}>
      {ZONES.map(z => (
        <button key={z.id} onClick={()=>onChange(z.id)} style={{
          flex:1, padding:'6px 0', borderRadius:4,
          fontFamily:"'Archivo',sans-serif", fontWeight:800, fontSize:11, letterSpacing:'0.06em',
          background:`${z.color}20`, color:z.color,
          border:`1px solid ${value===z.id?z.color:'transparent'}`,
          cursor:'pointer', opacity:value===z.id?1:0.55,
        }}>S{z.id}</button>
      ))}
    </div>
  );
}

function SsSelector({ value, onChange }) {
  return (
    <div style={{ display:'flex', gap:4 }}>
      {SS_OPTS.map(s => {
        const on = (value||'sit')===s.id;
        return (
          <button key={s.id} onClick={()=>onChange(s.id)} style={{
            flex:1, padding:'7px 0', borderRadius:4,
            fontFamily:"'Archivo',sans-serif", fontWeight:700, fontSize:11,
            background:on?`${s.color}20`:'transparent',
            color:on?s.color:PC.ink2,
            border:`1px solid ${on?s.color:PC.line}`,
            cursor:'pointer', textTransform:'uppercase', letterSpacing:'0.06em',
          }}>{s.label}</button>
        );
      })}
    </div>
  );
}

// ± 1-sekund-stepper for tid-felter. Mountes på høyre side av input.
function TimeField({ value, onChange, onCommit, onStep, disabled, title }) {
  const btnStyle = {
    width: 22, padding: 0, flex: 1,
    background: PC.bg, border: `1px solid ${PC.line}`,
    color: PC.ink2, fontSize: 9, lineHeight: 1,
    cursor: disabled ? 'not-allowed' : 'pointer',
    opacity: disabled ? 0.4 : 1,
    display: 'flex', alignItems: 'center', justifyContent: 'center',
  };
  return (
    <div style={{ display:'flex', alignItems:'stretch', opacity: disabled ? 0.5 : 1 }}>
      <input style={{ ...monoStyle, borderTopRightRadius:0, borderBottomRightRadius:0, borderRight:'none' }}
        value={value} disabled={disabled} title={title}
        onChange={e=>onChange(e.target.value)}
        onBlur={e=>onCommit(e.target.value)}
        onKeyDown={e=>{ if(e.key==='Enter') e.target.blur(); }} />
      <div style={{ display:'flex', flexDirection:'column', width:22 }}>
        <button type="button" disabled={disabled} onMouseDown={e=>e.preventDefault()}
          onClick={()=>onStep(+1)} title="+1 sek"
          style={{ ...btnStyle, borderTopRightRadius:4, borderBottomWidth:0 }}>▲</button>
        <button type="button" disabled={disabled} onMouseDown={e=>e.preventDefault()}
          onClick={()=>onStep(-1)} title="−1 sek"
          style={{ ...btnStyle, borderBottomRightRadius:4 }}>▼</button>
      </div>
    </div>
  );
}

const delBtn = onClick => (
  <button onClick={onClick} style={{
    width:'100%', padding:'8px', borderRadius:4,
    border:`1px solid rgba(200,22,12,0.3)`, background:'transparent',
    color:PC.z5, fontFamily:"'Archivo',sans-serif", fontWeight:700,
    fontSize:12, textTransform:'uppercase', letterSpacing:'0.08em', cursor:'pointer',
  }}>Slett</button>
);

function PartInspector({ part, dispatch, setSelection, onOpenGenerator }) {
  const addInterval = () => {
    const nid = uid();
    dispatch(s => { const p=s.parts.find(x=>x.id===part.id); if(p) p.intervals.push({ id:nid, name:'Intervall', duration:60, zone:2, bpm:120, sitStand:'sit', notes:'' }); });
    setSelection({ type:'interval', id:nid, partId:part.id });
  };
  return (
    <>
      <div style={{ padding:'14px 18px', borderBottom:`1px solid ${PC.line}`, display:'flex', alignItems:'center', justifyContent:'space-between', flexShrink:0 }}>
        <span style={{ fontFamily:"'Archivo',sans-serif", fontWeight:700, fontSize:10, letterSpacing:'0.18em', textTransform:'uppercase', color:PC.muted }}>Del</span>
        <span style={{ width:8, height:8, borderRadius:'50%', background:ptColor(part.type) }} />
      </div>
      <div style={{ flex:1, overflowY:'auto', padding:16 }}>
        <PField label="Navn">
          <input style={iStyle} value={part.name}
            onChange={e=>dispatch(s=>{const p=s.parts.find(x=>x.id===part.id);if(p)p.name=e.target.value;})} />
        </PField>
        <PField label="Type">
          <select style={iStyle} value={part.type}
            onChange={e=>dispatch(s=>{const p=s.parts.find(x=>x.id===part.id);if(p)p.type=e.target.value;})}>
            {PART_TYPES.map(pt=><option key={pt.id} value={pt.id}>{pt.label}</option>)}
          </select>
        </PField>
        <PField label="Varighet">
          <div style={{ ...monoStyle, color:PC.accent, cursor:'default' }}>{fmt(partDur(part))} · {part.intervals.length} intervaller</div>
        </PField>
        <button onClick={addInterval} style={{ width:'100%', padding:'8px', marginBottom:8, borderRadius:4, border:`1px solid ${PC.line2}`, background:'transparent', color:PC.ink2, fontFamily:"'Archivo',sans-serif", fontWeight:700, fontSize:12, textTransform:'uppercase', letterSpacing:'0.08em', cursor:'pointer' }}>
          + Legg til intervall
        </button>
        {part.type==='interval' && (
          <button onClick={()=>onOpenGenerator(part.id)} style={{ width:'100%', padding:'8px', marginBottom:8, borderRadius:4, border:`1px solid ${PC.line2}`, background:'transparent', color:PC.ink2, fontFamily:"'Archivo',sans-serif", fontWeight:700, fontSize:12, textTransform:'uppercase', letterSpacing:'0.08em', cursor:'pointer' }}>
            ⚡ Generator
          </button>
        )}
        <div style={{ borderTop:`1px solid ${PC.line}`, paddingTop:10 }}>
          {delBtn(()=>{ dispatch(s=>{s.parts=s.parts.filter(x=>x.id!==part.id);}); setSelection(null); })}
        </div>
      </div>
    </>
  );
}

function IntervalInspector({ iv, partId, session, dispatch, setSelection }) {
  const [showCues, setShowCues] = React.useState(false);
  const [durVal, setDurVal] = React.useState(fmt(iv.duration));
  const [fraVal, setFraVal] = React.useState('');
  const [tilVal, setTilVal] = React.useState('');
  const [warn, setWarn]     = React.useState({ fra:null, til:null, dur:null });

  // Posisjon i økten — beregnes fra session.
  const timing = React.useMemo(()=>ivStartEnd(session, iv.id), [session, iv.id]);
  const startSec = timing?.start ?? 0;
  const endSec   = timing?.end   ?? iv.duration;

  // Sjekk om dette er første/siste intervall (begrenser Fra/Til-redigering).
  const allIvs = React.useMemo(()=>{ const out=[]; for(const p of session.parts) for(const i of p.intervals) out.push(i); return out; }, [session.parts]);
  const ivIdx     = allIvs.findIndex(x=>x.id===iv.id);
  const isFirstIv = ivIdx <= 0;
  const isLastIv  = ivIdx === allIvs.length-1;

  React.useEffect(()=>{ setDurVal(fmt(iv.duration)); }, [iv.id, iv.duration]);
  React.useEffect(()=>{ setFraVal(fmt(startSec)); setTilVal(fmt(endSec)); }, [iv.id, startSec, endSec]);

  // Auto-fjern varsler.
  React.useEffect(()=>{
    if (warn.fra||warn.til||warn.dur) {
      const t = setTimeout(()=>setWarn({ fra:null, til:null, dur:null }), 4500);
      return ()=>clearTimeout(t);
    }
  }, [warn]);

  const upd = patch => dispatch(s=>{
    const p=s.parts.find(x=>x.id===partId); if(!p) return;
    const i=p.intervals.find(x=>x.id===iv.id); if(i) Object.assign(i, patch);
  });

  // Sett varighet med klamping (min MIN_IV).
  const commitDur = txt => {
    const parsed = parseDur(txt);
    if (parsed < MIN_IV) {
      upd({ duration: MIN_IV });
      setDurVal(fmt(MIN_IV));
      setWarn(w => ({ ...w, dur:`Minimum varighet er ${MIN_IV}s` }));
    } else {
      upd({ duration: parsed });
      setDurVal(fmt(parsed));
    }
  };

  // Sett Fra — flytter grensen mot forrige intervall.
  const commitFra = txt => {
    const parsed = parseDur(txt);
    let resWarn = null;
    dispatch(s => { const r = adjustIvStart(s, iv.id, parsed); if (r?.warn) resWarn = r.warn; if (r?.error) resWarn = r.error; });
    if (resWarn) setWarn(w => ({ ...w, fra: resWarn }));
  };
  // Sett Til — flytter grensen mot neste intervall (eller utvider hvis siste).
  const commitTil = txt => {
    const parsed = parseDur(txt);
    let resWarn = null;
    dispatch(s => { const r = adjustIvEnd(s, iv.id, parsed); if (r?.warn) resWarn = r.warn; if (r?.error) resWarn = r.error; });
    if (resWarn) setWarn(w => ({ ...w, til: resWarn }));
  };

  // Nytt intervall rett etter — arver sone/BPM/posisjon for rask fortløpende innlegging.
  const addAfter = () => {
    const nid = uid();
    dispatch(s => {
      const p = s.parts.find(x=>x.id===partId); if(!p) return;
      const idx = p.intervals.findIndex(x=>x.id===iv.id); if(idx<0) return;
      p.intervals.splice(idx+1, 0, { id:nid, name:'Intervall', duration:60, zone:iv.zone, bpm:iv.bpm, sitStand:iv.sitStand, notes:'' });
    });
    setSelection({ type:'interval', id:nid, partId });
  };

  // Dupliser dette intervallet (full kopi, samme navn, rett etter).
  const duplicate = () => {
    const nid = uid();
    dispatch(s => {
      const p = s.parts.find(x=>x.id===partId); if(!p) return;
      const idx = p.intervals.findIndex(x=>x.id===iv.id); if(idx<0) return;
      p.intervals.splice(idx+1, 0, { ...deepCopy(iv), id:nid });
    });
    setSelection({ type:'interval', id:nid, partId });
  };

  const warnStyle = { fontFamily:"'Archivo',sans-serif", fontSize:10, color:PC.z4, marginTop:4, lineHeight:1.4 };

  return (
    <>
      <div style={{ padding:'14px 18px', borderBottom:`1px solid ${PC.line}`, display:'flex', alignItems:'center', justifyContent:'space-between', flexShrink:0 }}>
        <span style={{ fontFamily:"'Archivo',sans-serif", fontWeight:700, fontSize:10, letterSpacing:'0.18em', textTransform:'uppercase', color:PC.muted }}>Intervall</span>
        <span style={{ width:8, height:8, borderRadius:'50%', background:zc(iv.zone) }} />
      </div>
      <div style={{ flex:1, overflowY:'auto', padding:16 }}>
        <PField label="Navn">
          <input style={iStyle} value={iv.name} onChange={e=>upd({name:e.target.value})} />
        </PField>

        {/* Fra · Til — flytter grensen mot nabointervaller */}
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:8 }}>
          <PField label="Fra">
            <TimeField value={fraVal} onChange={setFraVal} onCommit={commitFra}
              onStep={d => commitFra(fmt(Math.max(0, startSec + d)))}
              disabled={isFirstIv}
              title={isFirstIv ? 'Første intervall starter alltid 00:00' : 'mm:ss eller sekunder. Endrer forrige intervalls lengde.'} />
            {warn.fra && <div style={warnStyle}>{warn.fra}</div>}
          </PField>
          <PField label="Til">
            <TimeField value={tilVal} onChange={setTilVal} onCommit={commitTil}
              onStep={d => commitTil(fmt(Math.max(0, endSec + d)))}
              title="mm:ss eller sekunder. Endrer dette intervallets lengde, justerer neste tilsvarende." />
            {warn.til && <div style={warnStyle}>{warn.til}</div>}
          </PField>
        </div>

        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:8 }}>
          <PField label="Varighet">
            <TimeField value={durVal} onChange={setDurVal} onCommit={commitDur}
              onStep={d => commitDur(fmt(Math.max(MIN_IV, iv.duration + d)))}
              title="mm:ss eller bare sekunder (f.eks. 45 = 45 sek)" />
            {warn.dur && <div style={warnStyle}>{warn.dur}</div>}
          </PField>
          <PField label="BPM">
            <input style={monoStyle} type="number" min="40" max="250" value={iv.bpm}
              onChange={e=>upd({bpm:parseInt(e.target.value)||0})} />
          </PField>
        </div>
        <PField label="Intensitetssone">
          <ZoneSelector value={iv.zone} onChange={v=>upd({zone:v})} />
        </PField>
        <PField label="Posisjon">
          <SsSelector value={iv.sitStand} onChange={v=>upd({sitStand:v})} />
        </PField>
        <PField label="Notater">
          <textarea style={{ ...iStyle, minHeight:56, resize:'vertical', lineHeight:1.5, fontSize:12 }}
            value={iv.notes||''} onChange={e=>upd({notes:e.target.value})} placeholder="Instruksjoner, koreografi…" />
        </PField>

        {/* Cues — collapsed by default */}
        <div style={{ border:`1px dashed ${PC.line2}`, borderRadius:4, padding:'10px 12px', marginBottom:12 }}>
          <div onClick={()=>setShowCues(x=>!x)} style={{ display:'flex', justifyContent:'space-between', alignItems:'center', cursor:'pointer', marginBottom:showCues?8:0 }}>
            <span style={{ fontFamily:"'Archivo',sans-serif", fontWeight:700, fontSize:9, letterSpacing:'0.14em', textTransform:'uppercase', color:PC.muted }}>
              {showCues?'▾':'▸'} Cues · selvkjørt (valgfritt)
            </span>
          </div>
          {showCues && (
            <div style={{ fontSize:11, color:PC.dim, fontStyle:'italic' }}>
              {(iv.cues||[]).length===0 ? 'Ingen cues ennå' : (iv.cues||[]).map((c,i)=>(
                <div key={i} style={{ display:'grid', gridTemplateColumns:'44px 1fr', gap:8, padding:'4px 0', borderTop:i>0?`1px solid ${PC.line}`:'none' }}>
                  <span style={{ fontFamily:"'Space Mono',monospace", fontSize:11, color:PC.accent, fontWeight:700 }}>+{c.atSecond}s</span>
                  <span style={{ fontSize:12, color:PC.ink, fontStyle:'normal' }}>{c.text}</span>
                </div>
              ))}
            </div>
          )}
        </div>

        <div style={{ borderTop:`1px solid ${PC.line}`, paddingTop:10, display:'flex', flexDirection:'column', gap:8 }}>
          <button onClick={addAfter} style={{ width:'100%', padding:'8px', borderRadius:4, border:`1px solid ${PC.line2}`, background:'transparent', color:PC.ink2, fontFamily:"'Archivo',sans-serif", fontWeight:700, fontSize:12, textTransform:'uppercase', letterSpacing:'0.08em', cursor:'pointer' }}>
            + Nytt intervall
          </button>
          <button onClick={duplicate} style={{ width:'100%', padding:'8px', borderRadius:4, border:`1px solid ${PC.line2}`, background:'transparent', color:PC.ink2, fontFamily:"'Archivo',sans-serif", fontWeight:700, fontSize:12, textTransform:'uppercase', letterSpacing:'0.08em', cursor:'pointer' }}>
            ⧉ Dupliser
          </button>
          {delBtn(()=>{ dispatch(s=>{const p=s.parts.find(x=>x.id===partId);if(p)p.intervals=p.intervals.filter(x=>x.id!==iv.id);}); setSelection(null); })}
        </div>
      </div>
    </>
  );
}

function TrackInspector({ track, dispatch, setSelection }) {
  const upd = patch => dispatch(s=>{ const t=s.tracks.find(x=>x.id===track.id); if(t) Object.assign(t,patch); });

  const endSec = track.startSec + track.durationSec;

  const [startVal,  setStartVal]  = React.useState(fmt(track.startSec));
  const [endVal,    setEndVal]    = React.useState(fmt(endSec));
  const [offsetVal, setOffsetVal] = React.useState(fmt(track.startOffset||0));
  const [durVal,    setDurVal]    = React.useState(fmt(track.durationSec));
  React.useEffect(()=>{ setStartVal(fmt(track.startSec)); },          [track.id, track.startSec]);
  React.useEffect(()=>{ setEndVal(fmt(track.startSec + track.durationSec)); }, [track.id, track.startSec, track.durationSec]);
  React.useEffect(()=>{ setOffsetVal(fmt(track.startOffset||0)); },   [track.id, track.startOffset]);
  React.useEffect(()=>{ setDurVal(fmt(track.durationSec)); },         [track.id, track.durationSec]);

  const commitStart  = txt => { const v = Math.max(0, parseDur(txt)); upd({startSec: v}); setStartVal(fmt(v)); };
  const commitEnd    = txt => { const v = Math.max(track.startSec + 10, parseDur(txt)); upd({durationSec: v - track.startSec}); setEndVal(fmt(v)); };
  const commitOffset = txt => { const v = Math.max(0, Math.min(track.durationSec - 1, parseDur(txt))); upd({startOffset: v}); setOffsetVal(fmt(v)); };
  const commitDur    = txt => { const v = Math.max(10, parseDur(txt)); upd({durationSec: v}); setDurVal(fmt(v)); };

  return (
    <>
      <div style={{ padding:'14px 18px', borderBottom:`1px solid ${PC.line}`, display:'flex', alignItems:'center', justifyContent:'space-between', flexShrink:0 }}>
        <span style={{ fontFamily:"'Archivo',sans-serif", fontWeight:700, fontSize:10, letterSpacing:'0.18em', textTransform:'uppercase', color:PC.muted }}>Musikkspor</span>
        <span style={{ width:8, height:8, borderRadius:'50%', background:PC.accent }} />
      </div>
      <div style={{ flex:1, overflowY:'auto', padding:16 }}>
        <PField label="Tittel"><input style={iStyle} value={track.title} onChange={e=>upd({title:e.target.value})} /></PField>
        <PField label="Artist"><input style={iStyle} value={track.artist} onChange={e=>upd({artist:e.target.value})} /></PField>
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:8 }}>
          <PField label="Start i økten">
            <TimeField value={startVal} onChange={setStartVal} onCommit={commitStart}
              onStep={d => commitStart(fmt(Math.max(0, track.startSec + d)))}
              title="mm:ss eller bare sekunder (f.eks. 45 = 45 sek)" />
          </PField>
          <PField label="Slutter i økten">
            <TimeField value={endVal} onChange={setEndVal} onCommit={commitEnd}
              onStep={d => commitEnd(fmt(Math.max(track.startSec + 10, endSec + d)))}
              title="Når sporet slutter i økten — justerer lengden tilsvarende" />
          </PField>
        </div>
        <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:8 }}>
          <PField label="Lengde">
            <TimeField value={durVal} onChange={setDurVal} onCommit={commitDur}
              onStep={d => commitDur(fmt(Math.max(10, track.durationSec + d)))}
              title="mm:ss eller bare sekunder (f.eks. 90 = 90 sek)" />
          </PField>
          <PField label="BPM"><input style={monoStyle} type="number" min="40" max="250" value={track.bpm} onChange={e=>upd({bpm:parseInt(e.target.value)||0})} /></PField>
        </div>
        <PField label="Spilles fra">
          <TimeField value={offsetVal} onChange={setOffsetVal} onCommit={commitOffset}
            onStep={d => commitOffset(fmt(Math.max(0, (track.startOffset||0) + d)))}
            title="Hvor langt inn i låten avspillingen starter — mm:ss eller bare sekunder" />
        </PField>
        <PField label="Notater">
          <textarea style={{ ...iStyle, minHeight:52, resize:'vertical', lineHeight:1.5, fontSize:12 }}
            value={track.notes||''} onChange={e=>upd({notes:e.target.value})} placeholder="Koreografi, instruksjoner…" />
        </PField>
        <div style={{ borderTop:`1px solid ${PC.line}`, paddingTop:10 }}>
          {delBtn(()=>{ dispatch(s=>{s.tracks=s.tracks.filter(x=>x.id!==track.id);}); setSelection(null); })}
        </div>
      </div>
    </>
  );
}

function Inspector({ selection, session, dispatch, setSelection, onOpenGenerator }) {
  let content = null;
  if (!selection) {
    content = (
      <div style={{ flex:1, display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', padding:20, textAlign:'center' }}>
        <div style={{ fontSize:28, opacity:0.12, marginBottom:8 }}>←</div>
        <div style={{ fontFamily:"'Archivo',sans-serif", fontSize:11, color:PC.muted, lineHeight:1.7 }}>Klikk på en del, et intervall eller et musikkspor for å redigere</div>
      </div>
    );
  } else if (selection.type==='part') {
    const part = session.parts.find(p=>p.id===selection.id);
    if (part) content = <PartInspector part={part} dispatch={dispatch} setSelection={setSelection} onOpenGenerator={onOpenGenerator} />;
  } else if (selection.type==='interval') {
    let iv=null, partId=null;
    for (const p of session.parts) { const f=p.intervals.find(i=>i.id===selection.id); if(f){iv=f;partId=p.id;break;} }
    if (iv) content = <IntervalInspector iv={iv} partId={partId} session={session} dispatch={dispatch} setSelection={setSelection} />;
  } else if (selection.type==='track') {
    const track = session.tracks.find(t=>t.id===selection.id);
    if (track) content = <TrackInspector track={track} dispatch={dispatch} setSelection={setSelection} />;
  }

  return (
    <div style={{ width:280, minWidth:280, background:PC.paper, borderLeft:`1px solid ${PC.line}`, display:'flex', flexDirection:'column', overflow:'hidden' }}>
      {!selection && (
        <div style={{ padding:'14px 18px', borderBottom:`1px solid ${PC.line}`, flexShrink:0 }}>
          <span style={{ fontFamily:"'Archivo',sans-serif", fontWeight:700, fontSize:10, letterSpacing:'0.18em', textTransform:'uppercase', color:PC.muted }}>Detaljer</span>
        </div>
      )}
      {content}
    </div>
  );
}

Object.assign(window, { Inspector });
