/* global React */
// =========================================================================
// DESKTOP — window manager, taskbar, drag, focus, minimize
// =========================================================================

const { useState: useDtState, useEffect: useDtEffect, useRef: useDtRef, useCallback: useDtCallback } = React;

const APPS = {
  tracker:   { label: 'TRACKER',    icon: 'IconTracker',   title: 'C:\\SLEEP\\TRACKER.EXE',     w: 720, h: 560, comp: 'TrackerWindow' },
  cycles:    { label: 'CYCLES',     icon: 'IconCycle',     title: 'C:\\SLEEP\\CYCLES.HLP',      w: 700, h: 580, comp: 'CyclesWindow' },
  disorders: { label: 'DISORDERS',  icon: 'IconDisorders', title: 'C:\\SLEEP\\DISORDERS.HLP',   w: 680, h: 560, comp: 'DisordersWindow' },
  quality:   { label: 'QUALITY',    icon: 'IconQuality',   title: 'C:\\SLEEP\\HYGIENE.HLP',     w: 680, h: 580, comp: 'QualityWindow' },
  myths:     { label: 'MYTHS',      icon: 'IconMyths',     title: 'C:\\SLEEP\\MYTHS.HLP',       w: 660, h: 580, comp: 'MythsWindow' },
  ambience:  { label: 'AMBIENCE',   icon: 'IconAmbience',  title: 'C:\\SLEEP\\AMBIENCE.EXE',    w: 760, h: 600, comp: 'AmbienceWindow' },
  redalert:  { label: 'RED ALERT',  icon: 'IconAlert',     title: 'C:\\SLEEP\\RED_ALERT.HLP',   w: 640, h: 520, comp: 'DrowsinessRedAlertWindow' },
  about:     { label: 'README',     icon: 'IconQuality',   title: 'C:\\SOMNIA\\README.TXT',     w: 540, h: 460, comp: 'AboutWindow' },
};

const ICON_ORDER = ['tracker', 'cycles', 'disorders', 'quality', 'myths', 'ambience', 'redalert'];

// ── Walking sheep on the desktop ─────────────────────────────────────────
const SHEEP_SPRITES = [
  { Comp: 'SheepProfile', size: 78, w: 78 },
  { Comp: 'SheepProfileJump', size: 84, w: 84 },
];
const SHEEP_W = Math.max(...SHEEP_SPRITES.map((s) => s.w));

function JumpingSheep({ enabled, count = 4 }) {
  const laneRef = useDtRef(null);

  useDtEffect(() => {
    if (!enabled) return undefined;

    const lane = laneRef.current;
    if (!lane) return undefined;

    const specs = Array.from({ length: count }, (_, i) => ({
      duration: 10 + i * 1.6,
      delay: -((10 + i * 1.6) / count) * i,
      hopOffset: i * 0.12,
    }));

    const tick = () => {
      const walkers = lane.querySelectorAll('.sheep-walker');
      const laneW = lane.clientWidth || window.innerWidth;
      const span = laneW + SHEEP_W * 2;
      const now = performance.now() / 1000;

      walkers.forEach((walker, i) => {
        const spec = specs[i];
        if (!spec) return;
        const sw = Number(walker.dataset.sheepW) || SHEEP_W;
        const t = now - spec.delay;
        const phase = ((t % spec.duration) + spec.duration) % spec.duration / spec.duration;
        const x = laneW + sw - phase * (laneW + sw * 2);
        walker.style.transform = `translate3d(${x}px, 0, 0)`;
        const hopper = walker.querySelector('.sheep-hopper');
        if (hopper) {
          const hopPhase = ((t + spec.hopOffset) % 0.8) / 0.8;
          hopper.style.transform = `translateY(${hopPhase < 0.5 ? -18 : 0}px)`;
        }
      });
    };

    tick();
    const id = window.setInterval(tick, 32);
    return () => window.clearInterval(id);
  }, [enabled, count]);

  if (!enabled) return null;

  return (
    <div
      className="sheep-lane"
      ref={laneRef}
      aria-hidden="true"
      style={{
        position: 'absolute',
        bottom: 70,
        left: 0,
        right: 0,
        height: 120,
        overflow: 'hidden',
        pointerEvents: 'none',
        zIndex: 2,
      }}>
      {Array.from({ length: count }).map((_, i) => {
        const sprite = SHEEP_SPRITES[i % SHEEP_SPRITES.length];
        const Comp = window[sprite.Comp];
        return (
          <div key={i} className="sheep-walker" data-sheep-w={sprite.w}>
            <div className="sheep-hopper">
              <Comp size={sprite.size} />
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ── Desktop Icon ─────────────────────────────────────────────────────────
function DesktopIcon({ id, app, onOpen }) {
  const Icon = window[app.icon];
  return (
    <button className="dicon" onDoubleClick={() => onOpen(id)} onClick={(e) => { if (e.detail >= 1 && e.type === 'click') {} }} aria-label={app.label}>
      <div className="dicon-art">
        <Icon size={32} />
      </div>
      <div className="dicon-label">{app.label}</div>
    </button>
  );
}

// Modified to open on single click for usability — but with a focus first.
function DesktopIconSingle({ id, app, onOpen }) {
  const Icon = window[app.icon];
  return (
    <button className="dicon" onClick={() => onOpen(id)} aria-label={app.label}>
      <div className="dicon-art">
        <Icon size={32} />
      </div>
      <div className="dicon-label">{app.label}</div>
    </button>
  );
}

const MIN_WIN_W = 320;
const MIN_WIN_H = 240;
const TASKBAR_H = 44;
const DESKTOP_PAD = 8;

const clampWinValue = (value, min, max) => Math.max(min, Math.min(max, value));

// ── Window with drag + resize ────────────────────────────────────────────
function Win({ win, app, z, focused, onFocus, onClose, onMinimize, onMove }) {
  const ref = useDtRef(null);
  const viewportW = window.innerWidth || app.w;
  const viewportH = window.innerHeight || app.h;
  const isMobile = viewportW <= 760;
  const minWinW = isMobile ? 0 : MIN_WIN_W;
  const minWinH = isMobile ? 0 : MIN_WIN_H;
  const winW = isMobile
    ? viewportW - DESKTOP_PAD * 2
    : Math.min(win.w || app.w, Math.max(minWinW, viewportW - DESKTOP_PAD * 2));
  const winH = isMobile
    ? viewportH - TASKBAR_H - DESKTOP_PAD * 2
    : Math.min(win.h || app.h, Math.max(minWinH, viewportH - TASKBAR_H - DESKTOP_PAD * 2));

  const startDrag = (e) => {
    if (isMobile || (e.button != null && e.button !== 0) || e.target.closest('.window-controls')) return;
    e.preventDefault();
    onFocus();
    const startX = e.clientX, startY = e.clientY;
    const startL = win.x, startT = win.y;
    const move = (ev) => {
      onMove(win.id, {
        x: clampWinValue(startL + ev.clientX - startX, 0, Math.max(0, window.innerWidth - winW - DESKTOP_PAD)),
        y: clampWinValue(startT + ev.clientY - startY, 0, Math.max(0, window.innerHeight - winH - TASKBAR_H - DESKTOP_PAD)),
      });
    };
    const up = () => {
      window.removeEventListener('pointermove', move);
      window.removeEventListener('pointerup', up);
    };
    window.addEventListener('pointermove', move);
    window.addEventListener('pointerup', up);
  };

  if (win.minimized) return null;
  const Comp = window[app.comp];

  const startResize = (e) => {
    if (isMobile || (e.button != null && e.button !== 0)) return;
    e.preventDefault();
    e.stopPropagation();
    onFocus();
    const startX = e.clientX, startY = e.clientY;
    const startW = winW, startH = winH;
    const move = (ev) => {
      const maxW = Math.max(MIN_WIN_W, window.innerWidth - win.x - DESKTOP_PAD);
      const maxH = Math.max(MIN_WIN_H, window.innerHeight - win.y - TASKBAR_H - DESKTOP_PAD);
      onMove(win.id, {
        w: clampWinValue(startW + ev.clientX - startX, MIN_WIN_W, maxW),
        h: clampWinValue(startH + ev.clientY - startY, MIN_WIN_H, maxH),
      });
    };
    const up = () => {
      window.removeEventListener('pointermove', move);
      window.removeEventListener('pointerup', up);
    };
    window.addEventListener('pointermove', move);
    window.addEventListener('pointerup', up);
  };

  return (
    <div className="window"
      ref={ref}
      style={{
        left: win.x, top: win.y,
        width: winW, height: winH,
        maxWidth: 'calc(100vw - 20px)',
        maxHeight: 'calc(100vh - 80px)',
        zIndex: z,
        outline: focused ? '0' : 'none',
      }}
      onMouseDown={onFocus}>
      <div className="window-title" onPointerDown={startDrag}>
        <div style={{display: 'flex', alignItems: 'center', gap: 6, overflow: 'hidden', flex: 1}}>
          <div style={{width: 16, height: 16, flexShrink: 0}}>
            {React.createElement(window[app.icon], { size: 16 })}
          </div>
          <span className="window-title-text">{app.title}</span>
        </div>
        <div className="window-controls">
          <button className="wbtn" onClick={(e) => { e.stopPropagation(); onMinimize(); }} aria-label="minimize">_</button>
          <button className="wbtn close" onClick={(e) => { e.stopPropagation(); onClose(); }} aria-label="close">X</button>
        </div>
      </div>
      <div className="window-body" data-screen-label={app.label}>
        <Comp {...(win.props || {})} />
      </div>
      {!isMobile && (
        <button
          className="window-resize"
          onPointerDown={startResize}
          aria-label={`resize ${app.label} window`}
          title="Resize"
        />
      )}
    </div>
  );
}

// ── Boot screen ──────────────────────────────────────────────────────────
const BOOT_MSGS = [
  'INITIALIZING...',
  'LOADING DREAM BUFFER...',
  'CALIBRATING MELATONIN...',
  'MOUNTING /MOON...',
  'READY.',
];
const BOOT_STEP_MS = 480;

function Boot({ onDone }) {
  const [step, setStep] = useDtState(0);

  useDtEffect(() => {
    let i = 0;
    const iv = setInterval(() => {
      i++;
      if (i < BOOT_MSGS.length) setStep(i);
      else { clearInterval(iv); onDone(); }
    }, BOOT_STEP_MS);
    return () => clearInterval(iv);
  }, []);

  const progress = ((step + 1) / BOOT_MSGS.length) * 100;

  return (
    <div className="boot">
      <div style={{display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16}}>
        <img src="icons/icon-192.png" width={80} height={80} alt="" style={{imageRendering: 'pixelated'}} />
        <div className="boot-logo">SOMNIA</div>
      </div>
      <div className="boot-bar">
        <div className="boot-bar-fill" style={{ width: `${progress}%` }} />
      </div>
      <div className="boot-msg">{BOOT_MSGS[step]}</div>
      <div style={{position: 'absolute', bottom: 30, fontFamily: 'var(--font-pixel)', fontSize: 8, color: 'var(--ink-faint)', textAlign: 'center'}}>
        SOMNIA OS • PIXEL EDITION<br/>
        © STANFORD SLEEP & DREAMS OUTREACH
      </div>
    </div>
  );
}

Object.assign(window, { JumpingSheep, DesktopIconSingle, Win, Boot, APPS, ICON_ORDER });
