const { useState, useEffect, useRef, useLayoutEffect } = React;
const D = ms => ms * (window.__spd || 1);
const clamp = (v, a, b) => Math.max(a, Math.min(b, v));

function AppIcon({ id, size = 54 }) {
  const fs = { fontSize: size * 0.3 };
  const inner = {
    about: <span style={{ fontSize: size * 0.34 }}>AY</span>,
    projects: <div className="ic-fold"></div>,
    experience: <div className="ic-bars"><i></i><i></i><i></i></div>,
    skills: <span style={fs}>{'{ }'}</span>,
    resume: <span style={{ fontSize: size * 0.26 }}>CV</span>,
    contact: <span style={{ fontSize: size * 0.4 }}>@</span>,
    terminal: <span style={{ fontSize: size * 0.3 }}>&gt;_</span>
  }[id];
  return <div className={'ic ic-' + id} style={{ width: size, height: size }}>{inner}</div>;
}

function Win({ w, app, focused, mobile, vp, onFocus, onClose, onGone, onMin, onMax, onRect, getDock, children }) {
  const ref = useRef();
  const prevMin = useRef(w.min);
  useLayoutEffect(() => {
    const el = ref.current, r = el.getBoundingClientRect();
    if (w.origin) {
      const dx = w.origin.x - (r.left + r.width / 2), dy = w.origin.y - (r.top + r.height / 2);
      el.animate([{ transform: `translate(${dx}px,${dy}px) scale(.06)`, opacity: 0 }, { opacity: 1, offset: .35 }, { transform: 'none', opacity: 1 }], { duration: D(560), easing: 'cubic-bezier(.2,1,.3,1)' });
    } else {
      el.animate([{ transform: 'translateY(14px) scale(.96)', opacity: 0 }, { transform: 'none', opacity: 1 }], { duration: D(420), easing: 'cubic-bezier(.2,1,.3,1)' });
    }
  }, []);
  useEffect(() => {
    if (prevMin.current === w.min) return;
    prevMin.current = w.min;
    const el = ref.current;
    el.getAnimations().forEach(a => a.cancel());
    el.style.visibility = '';
    const r = el.getBoundingClientRect(), t = getDock(w.id);
    const dx = t.x - (r.left + r.width / 2), dy = t.y - (r.top + r.height / 2);
    const kf = [
      { transform: 'none', opacity: 1 },
      { transform: `translate(${dx * .35}px,${dy * .55}px) scale(.55,.4)`, opacity: .9, offset: .45 },
      { transform: `translate(${dx}px,${dy}px) scale(.05)`, opacity: 0 }
    ];
    if (w.min) {
      el.animate(kf, { duration: D(520), easing: 'cubic-bezier(.55,0,.25,1)', fill: 'forwards' }).onfinish = () => { el.style.visibility = 'hidden'; };
    } else {
      el.animate(kf.slice().reverse(), { duration: D(540), easing: 'cubic-bezier(.2,1,.3,1)' });
    }
  }, [w.min]);
  useEffect(() => {
    if (!w.closing) return;
    const a = ref.current.animate([{ opacity: 1, transform: 'none' }, { opacity: 0, transform: 'scale(.93) translateY(10px)' }], { duration: D(220), easing: 'cubic-bezier(.5,0,.75,0)', fill: 'forwards' });
    a.onfinish = () => onGone(w.id);
  }, [w.closing]);

  const drag = e => {
    onFocus();
    if (mobile || w.max || e.button !== 0 || e.target.closest('.wbtns')) return;
    const el = ref.current, sx = e.clientX, sy = e.clientY, ox = w.x, oy = w.y;
    let lx = sx, lt = performance.now(), nx = ox, ny = oy, idle;
    el.classList.add('dragging');
    const mv = ev => {
      nx = clamp(ox + ev.clientX - sx, -w.w + 120, vp.w - 120);
      ny = clamp(oy + ev.clientY - sy, 32, vp.h - 60);
      el.style.left = nx + 'px'; el.style.top = ny + 'px';
      const now = performance.now(), vx = (ev.clientX - lx) / Math.max(1, now - lt);
      lx = ev.clientX; lt = now;
      el.style.rotate = clamp(vx * 1.6, -3.5, 3.5) + 'deg';
      clearTimeout(idle); idle = setTimeout(() => { el.style.rotate = '0deg'; }, 70);
    };
    const up = () => {
      window.removeEventListener('pointermove', mv); window.removeEventListener('pointerup', up);
      clearTimeout(idle); el.style.rotate = '0deg'; el.classList.remove('dragging');
      onRect({ x: nx, y: ny });
    };
    window.addEventListener('pointermove', mv); window.addEventListener('pointerup', up);
  };
  const resize = e => {
    e.stopPropagation(); onFocus();
    const el = ref.current, sx = e.clientX, sy = e.clientY, ow = w.w, oh = w.h;
    let nw = ow, nh = oh;
    el.classList.add('dragging');
    const mv = ev => {
      nw = clamp(ow + ev.clientX - sx, 360, vp.w - w.x - 8); nh = clamp(oh + ev.clientY - sy, 260, vp.h - w.y - 90);
      el.style.width = nw + 'px'; el.style.height = nh + 'px';
    };
    const up = () => {
      window.removeEventListener('pointermove', mv); window.removeEventListener('pointerup', up);
      el.classList.remove('dragging'); onRect({ w: nw, h: nh });
    };
    window.addEventListener('pointermove', mv); window.addEventListener('pointerup', up);
  };

  let pos;
  if (mobile) pos = { left: 0, top: 30, width: vp.w, height: vp.h - 30 - 84 };
  else if (w.max) pos = { left: 8, top: 38, width: vp.w - 16, height: vp.h - 38 - 98 };
  else pos = { left: w.x, top: w.y, width: w.w, height: w.h };
  return (
    <div ref={ref} className={'win' + (focused ? ' focused' : '') + (mobile ? ' mob' : '')} style={{ ...pos, zIndex: w.z }} onPointerDown={onFocus} data-screen-label={app.title}>
      <div className="wbar" onPointerDown={drag} onDoubleClick={e => { if (!e.target.closest('.wbtns')) onMax(); }}>
        <div className="wbtns">
          <button className="wbtn c" onClick={onClose} aria-label="Close">×</button>
          <button className="wbtn" onClick={onMin} aria-label="Minimize">–</button>
          {!mobile && <button className="wbtn" onClick={onMax} aria-label="Maximize">+</button>}
        </div>
        <div className="wtitle"><span>{app.title}</span><em>~/{app.path}</em></div>
      </div>
      <div className="wbody">{children}</div>
      {!mobile && !w.max && <div className="wresize" onPointerDown={resize}></div>}
    </div>
  );
}

function Dock({ items, running, onOpen, refs, mobile }) {
  const [mx, setMx] = useState(null);
  const dref = useRef(), left = useRef(0);
  const base = mobile ? 42 : 50, maxS = mobile ? 42 : 80, gap = 8, pad = 10;
  const sizeFor = (i, extra) => {
    if (mx == null || mobile) return base;
    const c = left.current + pad + i * (base + gap) + base / 2 + extra;
    const d = Math.abs(mx - c);
    return base + (maxS - base) * Math.max(0, Math.cos(Math.min(d / 150, 1) * Math.PI / 2)) ** 1.6;
  };
  let idx = 0;
  return (
    <div className="dock-wrap">
      <div ref={dref} className="dock" style={{ height: base + 20, gap }}
        onMouseEnter={() => { left.current = dref.current.getBoundingClientRect().left; }}
        onMouseMove={e => setMx(e.clientX)} onMouseLeave={() => setMx(null)}>
        {items.map(it => {
          if (it === '|') { idx += 0; return <div key="sep" className="dsep"></div>; }
          const i = idx++, sepOffset = i >= items.indexOf('|') && items.indexOf('|') > -1 ? gap + 9 : 0;
          const s = sizeFor(i, sepOffset);
          return (
            <button key={it.id} ref={el => refs.current[it.id] = el} className={'ditem' + (running.includes(it.id) ? ' on' : '')} style={{ width: s, height: s }}
              onClick={e => onOpen(it.id, e.currentTarget)}>
              <AppIcon id={it.id} size={s} />
              <span className="tip">{it.title}</span>
              <i className="run"></i>
            </button>
          );
        })}
      </div>
    </div>
  );
}

function useClock() {
  const [t, setT] = useState(new Date());
  useEffect(() => { const i = setInterval(() => setT(new Date()), 1000 * 15); return () => clearInterval(i); }, []);
  return t;
}
const fmt = (d, o) => new Intl.DateTimeFormat('en-GB', { timeZone: 'Europe/Riga', ...o }).format(d);

function MenuBar({ focusedTitle, onOpen, onCtx }) {
  const t = useClock();
  return (
    <div className="menubar">
      <button className="mb-logo" onClick={e => onCtx(e)}><i></i>ata.os</button>
      <div className="mb-app" key={focusedTitle}>{focusedTitle || 'Desktop'}</div>
      <nav className="mb-nav">
        <button onClick={() => onOpen('projects')}>Projects</button>
        <button onClick={() => onOpen('experience')}>Experience</button>
        <button onClick={() => onOpen('resume')}>Resume</button>
        <button onClick={() => onOpen('contact')}>Contact</button>
      </nav>
      <div className="mb-right">
        <span className="mb-loc">Riga, LV</span>
        <span>{fmt(t, { weekday: 'short', day: 'numeric', month: 'short' })}</span>
        <span className="mb-time">{fmt(t, { hour: '2-digit', minute: '2-digit' })}</span>
      </div>
    </div>
  );
}

const BOOT_LINES = [
  ['ok', 'mounting /home/ata'],
  ['ok', 'loading projects — vizeradar, neoneloboost, amber'],
  ['ok', 'security baseline — iso 27001'],
  ['ok', 'linking riga, lv ⇄ istanbul, tr'],
  ['ok', 'starting desktop']
];
function Boot({ onReveal, onDone }) {
  const [n, setN] = useState(0), [name, setName] = useState(false), [out, setOut] = useState(false);
  const done = useRef(false);
  const finish = () => {
    if (done.current) return; done.current = true;
    setOut(true); onReveal(); setTimeout(onDone, D(900));
  };
  useEffect(() => {
    const ts = BOOT_LINES.map((_, i) => setTimeout(() => setN(i + 1), D(150 + i * 170)));
    ts.push(setTimeout(() => setName(true), D(1150)));
    ts.push(setTimeout(finish, D(2700)));
    return () => ts.forEach(clearTimeout);
  }, []);
  const words = CV.name.split(' ');
  let li = 0;
  return (
    <div className={'boot' + (out ? ' out' : '')} onClick={finish}>
      <div className="boot-log">
        <div className="bl dim">ata.os 26.10 — booting</div>
        {BOOT_LINES.slice(0, n).map(([k, v], i) => <div key={i} className="bl"><b>[ {k} ]</b> {v}</div>)}
      </div>
      <div className={'boot-name' + (name ? ' in' : '')}>
        {words.map((wd, wi) => (
          <span className="bw" key={wi}>{[...wd].map((c, ci) => <span key={ci} className="bc" style={{ transitionDelay: D(li++ * 32) + 'ms' }}>{c}</span>)}</span>
        ))}
        <div className="boot-sub">Software developer — Riga / Istanbul</div>
      </div>
      <div className="boot-bar"><i style={{ animationDuration: D(2600) + 'ms' }}></i></div>
      <div className="boot-skip">click to skip</div>
    </div>
  );
}

function Wallpaper({ kind }) {
  const ref = useRef();
  useEffect(() => {
    const mv = e => { if (ref.current) { ref.current.style.setProperty('--mx', e.clientX + 'px'); ref.current.style.setProperty('--my', e.clientY + 'px'); } };
    window.addEventListener('pointermove', mv);
    return () => window.removeEventListener('pointermove', mv);
  }, []);
  return (
    <div ref={ref} className={'wall wall-' + kind}>
      <div className="blob"></div><div className="blob b2"></div>
      {kind !== 'plain' && <div className="pat base"></div>}
      {kind !== 'plain' && <div className="pat spot"></div>}
      <div className="wm">
        <div className="wm-cap">Software developer · ex-cybersecurity</div>
        <div className="wm-name"><span>Ata Alp</span><span>Yıldırım</span></div>
      </div>
    </div>
  );
}

function Ctx({ at, items, onClose }) {
  useEffect(() => {
    const k = e => e.key === 'Escape' && onClose();
    window.addEventListener('keydown', k); return () => window.removeEventListener('keydown', k);
  }, []);
  const x = Math.min(at.x, innerWidth - 236), y = Math.min(at.y, innerHeight - items.length * 34 - 20);
  return (
    <div className="ctx-veil" onPointerDown={onClose} onContextMenu={e => { e.preventDefault(); onClose(); }}>
      <div className="ctx" style={{ left: x, top: y }} onPointerDown={e => e.stopPropagation()}>
        {items.map((it, i) => it === '-' ? <div key={i} className="ctx-sep"></div> :
          <button key={i} style={{ animationDelay: i * 18 + 'ms' }} onClick={() => { it.fn(); onClose(); }}><span>{it.label}</span>{it.hint && <em>{it.hint}</em>}</button>)}
      </div>
    </div>
  );
}

function Notif({ onView }) {
  const [out, setOut] = useState(false), [gone, setGone] = useState(false);
  const close = () => { setOut(true); setTimeout(() => setGone(true), D(450)); };
  useEffect(() => { const t = setTimeout(close, D(9000)); return () => clearTimeout(t); }, []);
  if (gone) return null;
  return (
    <div className={'notif' + (out ? ' out' : '')}>
      <AppIcon id="projects" size={38} />
      <div className="nt-txt">
        <div className="nt-top"><b>VizeRadar</b><span>now</span></div>
        <div>Live on the App Store — real-time Schengen appointment alerts.</div>
      </div>
      <div className="nt-acts">
        <button onClick={() => { onView(); close(); }}>View</button>
        <button onClick={close}>Close</button>
      </div>
    </div>
  );
}

function NowWidget({ onOpen }) {
  const t = useClock();
  return (
    <div className="widget">
      <div className="wg-time">{fmt(t, { hour: '2-digit', minute: '2-digit' })}<span>Riga</span></div>
      <div className="wg-row" onClick={() => onOpen('projects', { sel: 'amber' })}>
        <i className="pulse"></i><div><em>Freelance</em><b>Amber · Neoneloboost</b></div>
      </div>
      <div className="wg-row" onClick={() => onOpen('projects', { sel: 'vizeradar' })}>
        <i className="pulse live"></i><div><em>Live</em><b>VizeRadar</b></div>
      </div>
    </div>
  );
}

Object.assign(window, { D, clamp, AppIcon, Win, Dock, MenuBar, Boot, Wallpaper, Ctx, Notif, NowWidget, fmt });
