/* eslint-disable */
/* ============================================================
   ROVER — the Windows XP search pup, adopted by ATHARV.OS.
   (Replaces Bevel; same engine — corner dodge, bubbles, pets —
   new renderer driven by real Rover animations in assets/rover/.)
   Component keeps the BevelMascot name so app.jsx wiring holds.
============================================================ */

/* Animation library — durations must match assets/rover/manifest.json */
const ROVER_ANIMS = {
  idle:          { ms: 1584,  loop: true  },
  waiting:       { ms: 4158,  loop: true  },
  sleep:         { ms: 7854,  loop: true  },
  arrive:        { ms: 1848,  loop: false },
  lick:          { ms: 2904,  loop: false },
  excited:       { ms: 3036,  loop: false },
  dig:           { ms: 3234,  loop: false },
  'dig-success': { ms: 4488,  loop: false },
  sad:           { ms: 2310,  loop: false },
  read:          { ms: 1584,  loop: false },
  newspaper:     { ms: 1848,  loop: false },
  sniff:         { ms: 2574,  loop: false },
  leave:         { ms: 2574,  loop: false },
  photo:         { ms: 2772,  loop: false },
  chef:          { ms: 3036,  loop: false },
  dab:           { ms: 4158,  loop: false },
  football:      { ms: 2112,  loop: false },
  moviestar:     { ms: 1518,  loop: false },
};
const ROVER_TRICKS = ['chef', 'football', 'moviestar', 'dab', 'dig-success', 'excited'];
/* Legacy bevelReact() action names -> Rover animations */
const ROVER_ACT_MAP = { jump: 'excited', wag: 'excited', 'tilt-l': 'sniff', 'tilt-r': 'sniff', tilt: 'sniff', spin: 'excited', flop: 'lick', yawn: 'waiting' };

function RoverSprite({ anim, playId }) {
  // key remounts the img so a repeated one-shot restarts its WebP animation
  return (
    <img
      key={`${anim}-${playId}`}
      className="rover-img"
      src={`assets/rover/${anim}.webp`}
      alt=""
      draggable={false}
    />
  );
}

/* =========================================================== */

// Defense-in-depth: the bubble is an HTML sink and window.bevelReact() is a
// public global, so sanitize here — escape everything, then re-permit ONLY the
// <i>/<b> emphasis the persona lines use. Any injected tag renders as inert text.
function bevelSafeHtml(s) {
  if (typeof s !== 'string') return '';
  const esc = s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
  return esc.replace(/&lt;(\/?)(i|b)&gt;/g, '<$1$2>');
}

function BevelBubble({ message, corner }) {
  return (
    <div className={`bevel-bubble bb-${corner}`}>
      <span dangerouslySetInnerHTML={{__html: bevelSafeHtml(message)}}/>
      <span className="bevel-bubble-tail"/>
    </div>
  );
}

/* =========================================================== */

function BevelMascot({ phase, windows, mpPlaying, currentTrack, visible }) {
  const [pose, setPose] = React.useState('sit');           // sit | sleep
  const [oneShot, setOneShot] = React.useState(null);      // current one-shot anim key
  const [playId, setPlayId] = React.useState(0);           // bumps to restart repeated anims
  const [corner, setCorner] = React.useState('br');
  const [message, setMessage] = React.useState(null);
  const [hidden, setHidden] = React.useState(false);
  const [covered, setCovered] = React.useState(false);     // a maximized window fills the screen
  const [ctx, setCtx] = React.useState(null);              // {x, y} right-click menu
  const [petStreak, setPetStreak] = React.useState(0);
  const [petLifetime, setPetLifetime] = React.useState(() => {
    try { return parseInt(localStorage.getItem('atharvos.bevel.pets')||'0', 10) || 0; } catch { return 0; }
  });
  const [firstVisitDone, setFirstVisitDone] = React.useState(() => {
    try { return localStorage.getItem('atharvos.rover.greeted') === '1'; } catch { return false; }
  });

  const idleTimer = React.useRef(null);
  const sleepTimer = React.useRef(null);
  const messageTimer = React.useRef(null);
  const actionTimer = React.useRef(null);
  const varietyTimer = React.useRef(null);
  const lastSpoke = React.useRef(0);
  const sessionStart = React.useRef(Date.now());
  const poseRef = React.useRef(pose);
  poseRef.current = pose;
  // Manual sleep (context menu) is sticky: mouse activity must NOT wake him —
  // only clicking him, the menu's "Wake up", or calling him back.
  const manualSleepRef = React.useRef(false);

  /* ---- Preload the always-needed animations ---- */
  React.useEffect(() => {
    ['idle', 'sleep', 'lick', 'excited', 'arrive'].forEach(k => {
      const img = new Image();
      img.src = `assets/rover/${k}.webp`;
    });
  }, []);

  /* ---- Helpers ---- */
  const showMessage = (msg, duration = 6000, force = false) => {
    const now = Date.now();
    // Anti-Clippy: max 1 message per 8s unless forced (pets/clicks)
    if (!force && now - lastSpoke.current < 8000) return;
    // After 5 min, silent mode unless force
    if (!force && (now - sessionStart.current) > 5 * 60 * 1000) return;
    lastSpoke.current = now;
    setMessage(msg);
    clearTimeout(messageTimer.current);
    messageTimer.current = setTimeout(() => setMessage(null), duration);
  };

  const play = (key) => {
    const a = ROVER_ANIMS[key];
    if (!a) return;
    if (poseRef.current === 'sleep') { setPose('sit'); if (window.sfx) window.sfx.snoreStop(); }
    setOneShot(key);
    setPlayId(id => id + 1);
    clearTimeout(actionTimer.current);
    if (!a.loop) actionTimer.current = setTimeout(() => setOneShot(null), a.ms + 60);
  };

  const wake = () => {
    if (poseRef.current === 'sleep') {
      manualSleepRef.current = false;
      setPose('sit');
      play('waiting');
      showMessage('<i>yawn.</i> All quiet.', 4000);
    }
  };

  const resetIdle = () => {
    if (manualSleepRef.current) return; // he was told to sleep — stay down
    if (poseRef.current === 'sleep') wake();
    clearTimeout(idleTimer.current);
    clearTimeout(sleepTimer.current);
    idleTimer.current = setTimeout(() => {
      showMessage("Click anything. I'll sniff it out.", 5000);
    }, 22000);
    sleepTimer.current = setTimeout(() => {
      setPose('sleep');
      setOneShot(null);
      setMessage(null);
    }, 60000);
  };

  /* ---- First-visit greeting: Rover arrives with his bag ---- */
  React.useEffect(() => {
    if (phase !== 'desktop') return;
    const t1 = setTimeout(() => {
      if (!firstVisitDone) {
        play('arrive');
        showMessage("<i>Woof!</i> I'm Rover — you might remember me from Windows XP. New OS, same nose. First time here? <b>Right-click me → Take the tour.</b>", 9000, true);
        try { localStorage.setItem('atharvos.rover.greeted', '1'); } catch {}
        setFirstVisitDone(true);
      } else {
        play('excited');
        showMessage('Welcome back. <i>wag wag.</i>', 5000, true);
      }
    }, 2200);
    resetIdle();
    return () => {
      clearTimeout(t1);
      clearTimeout(idleTimer.current);
      clearTimeout(sleepTimer.current);
      clearTimeout(messageTimer.current);
      clearTimeout(actionTimer.current);
      clearTimeout(varietyTimer.current);
    };
    // eslint-disable-next-line
  }, [phase]);

  /* ---- Idle variety: occasionally stretch/sniff while awake ---- */
  React.useEffect(() => {
    if (phase !== 'desktop') return;
    const loop = () => {
      varietyTimer.current = setTimeout(() => {
        if (poseRef.current !== 'sleep' && !manualSleepRef.current && !document.hidden) {
          play(Math.random() < 0.5 ? 'waiting' : 'sniff');
          if (ROVER_ANIMS.waiting) actionTimer.current = setTimeout(() => setOneShot(null), 4300);
        }
        loop();
      }, 45000 + Math.random() * 45000);
    };
    loop();
    return () => clearTimeout(varietyTimer.current);
    // eslint-disable-next-line
  }, [phase]);

  /* ---- Mouse / keyboard activity ---- */
  React.useEffect(() => {
    if (phase !== 'desktop') return;
    const handler = () => resetIdle();
    window.addEventListener('mousemove', handler, { passive: true });
    window.addEventListener('keydown', handler, { passive: true });
    window.addEventListener('click', handler, { passive: true });
    return () => {
      window.removeEventListener('mousemove', handler);
      window.removeEventListener('keydown', handler);
      window.removeEventListener('click', handler);
    };
    // eslint-disable-next-line
  }, [phase, pose]);

  /* ---- Snore while asleep ---- */
  React.useEffect(() => {
    if (pose === 'sleep') {
      if (window.sfx) window.sfx.snoreStart();
      return () => { if (window.sfx) window.sfx.snoreStop(); };
    }
    if (window.sfx) window.sfx.snoreStop();
  }, [pose]);

  /* ---- Window-open reactions: animation + one-liner per app ---- */
  React.useEffect(() => {
    const handler = (e) => {
      if (manualSleepRef.current) return; // let him sleep through window openings
      const k = (e.detail && e.detail.appKey) || '';
      if (k.startsWith('project:')) {
        play('dig');
        showMessage('Digging into this one — every tab tells a story.', 5000, true);
        return;
      }
      // Each line showcases a real skill / achievement tied to the app he opened.
      const dialog = {
        about:       { msg: "Backend & AI Engineer — LangGraph agents on top of production FastAPI.", anim: 'sniff' },
        mycomputer:  { msg: "17 projects in here — and <i>3 are live products he shipped solo.</i>",       anim: 'sniff' },
        resume:      { msg: "OCI GenAI Professional. 390 passing tests on his copilot. Wrote it himself.", anim: 'read' },
        awards:      { msg: "1st place hunting real vulns across 17 gov sites. He's modest — look.",       anim: 'excited' },
        mediaplayer: { msg: 'Press play. He wired these embeds up too.',                                   anim: 'dab' },
        notepad:     { msg: 'Field notes from the <i>pahaad.</i>',                                         anim: 'read' },
        photos:      { msg: 'Mountains, mostly. I took some of these.',                                    anim: 'photo' },
        terminal:    { msg: "Linux is home turf — systemd, SSH hardening, the lot.",                       anim: 'sniff' },
        recycle:     { msg: "Don't worry — empty. <i>Mostly.</i>",                                         anim: 'sniff' },
        network:     { msg: "FastAPI + Docker + GitHub Actions. Go poke a live one.",                      anim: 'sniff' },
        ie:          { msg: 'Surfing in <i>1995</i>. Hold tight.',                                         anim: 'newspaper' },
        readme:      { msg: "Start here if it's your first visit.",                                        anim: 'read' },
        experience:  { msg: "Mirakalous + Royal Bank Pacific — he ships straight to prod.",                anim: 'newspaper' },
        skills:      { msg: "AI agents, RAG on pgvector, FastAPI, Docker — all dialed in.",                anim: 'chef' },
        solitaire:   { msg: 'Klondike. <i>One more game.</i>',                                             anim: 'excited' },
        chat:        { msg: "The <i>AI</i> him — RAG + Gemini, the whole pipeline is his. Ask it anything.", anim: 'excited' },
        minesweeper: { msg: 'Right-click to flag. <i>Trust me, I dig.</i>',                                anim: 'dig' },
        hiring:      { msg: "He's open to work — and you can book a call right in there.",                 anim: 'newspaper' },
        systems:     { msg: "Live uptime of his 3 deployed products. <i>Real</i> monitoring, not a mock.", anim: 'excited' },
        doom:        { msg: "He self-hosted DOOM in a sandboxed iframe. Overkill? <i>Absolutely.</i>",     anim: 'excited' },
      };
      const d = dialog[k];
      if (d) {
        play(d.anim);
        showMessage(d.msg, 6000, true);
      }
    };
    window.addEventListener('atharv-os:open', handler);
    const petHandler = () => { window.__atharvPetTrigger && window.__atharvPetTrigger(); };
    window.addEventListener('atharv-os:pet-bevel', petHandler);
    const showHandler = () => { setHidden(false); play('arrive'); showMessage('<i>Woof!</i> Missed me?', 4500, true); };
    window.addEventListener('atharv-os:rover-show', showHandler);
    return () => {
      window.removeEventListener('atharv-os:open', handler);
      window.removeEventListener('atharv-os:pet-bevel', petHandler);
      window.removeEventListener('atharv-os:rover-show', showHandler);
    };
    // eslint-disable-next-line
  }, []);

  /* ---- Global react hook (ContactForm, guestbook, future callers) ---- */
  React.useEffect(() => {
    window.bevelReact = (act, msg) => {
      if (manualSleepRef.current) return; // sleeping through it
      play(ROVER_ACT_MAP[act] || (ROVER_ANIMS[act] ? act : 'excited'));
      if (msg) showMessage(msg, 5000, true);
    };
    return () => { delete window.bevelReact; };
    // eslint-disable-next-line
  }, []);

  /* ---- Easter-egg keyboard sniffer ---- */
  React.useEffect(() => {
    let buf = '';
    let bufTimer = null;
    const reset = () => { buf = ''; };
    const handler = (e) => {
      if (e.target && e.target.matches && e.target.matches('input, textarea, [contenteditable]')) return;
      if (!/^[a-zA-Z]$/.test(e.key)) return;
      buf = (buf + e.key.toLowerCase()).slice(-24);
      clearTimeout(bufTimer);
      bufTimer = setTimeout(reset, 1800);
      if (buf.endsWith('devarv')) {
        play('excited');
        showMessage("That's his coding handle. <i>Woof.</i>", 5000, true);
        reset();
      } else if (buf.endsWith('hackathon')) {
        play('dig-success');
        showMessage('<i>Pahaad chad gaye!</i>', 5000, true);
        reset();
      } else if (buf.endsWith('rover') || buf.endsWith('bevel')) {
        play('excited');
        showMessage('Yes? <i>Woof woof.</i>', 4500, true);
        reset();
      }
    };
    window.addEventListener('keydown', handler);
    return () => {
      window.removeEventListener('keydown', handler);
      clearTimeout(bufTimer);
    };
  }, []);

  /* ---- Smart corner selection — measure real window rects so dragged
         windows count too (state coordinates go stale during drags) ---- */
  const cornerRef = React.useRef(corner);
  cornerRef.current = corner;
  React.useEffect(() => {
    if (phase !== 'desktop') return;
    const bevelW = 200, bevelH = 200, taskbarH = 40;
    const check = () => {
      // Context menus carry the .win look but aren't windows — especially
      // Rover's own menu, which opens on top of him and made him flee it.
      if (document.querySelector('.tray-ctx')) return;
      const rects = [...document.querySelectorAll('.win')]
        .filter(el => !el.classList.contains('tray-ctx'))
        .map(el => el.getBoundingClientRect());
      if (!rects.length) return;
      const vw = window.innerWidth, vh = window.innerHeight - taskbarH;
      const corners = {
        br: { x: vw - bevelW - 24, y: vh - bevelH - 8 },
        bl: { x: 24,               y: vh - bevelH - 8 },
        tr: { x: vw - bevelW - 24, y: 24 },
        tl: { x: 24,               y: 24 },
      };
      const overlapScore = (c) => rects.reduce((s, r) => {
        const ox = Math.max(0, Math.min(c.x + bevelW, r.right) - Math.max(c.x, r.left));
        const oy = Math.max(0, Math.min(c.y + bevelH, r.bottom) - Math.max(c.y, r.top));
        return s + ox * oy;
      }, 0);
      const threshold = bevelW * bevelH * 0.08;
      if (overlapScore(corners[cornerRef.current]) < threshold) return; // current corner is fine
      const ranked = Object.keys(corners)
        .map(k => ({ k, s: overlapScore(corners[k]) }))
        .sort((a, b) => a.s - b.s);
      if (ranked[0].k !== cornerRef.current) setCorner(ranked[0].k);
    };
    const iv = setInterval(check, 1200);
    const onUp = () => setTimeout(check, 60); // re-check right after a drag ends
    window.addEventListener('mouseup', onUp);
    check();
    return () => { clearInterval(iv); window.removeEventListener('mouseup', onUp); };
  }, [phase]);

  /* ---- Hide when a window is maximized (it fills the screen) ---- */
  React.useEffect(() => {
    if (phase !== 'desktop') return;
    const check = () => setCovered(!!document.querySelector('.win.maxed'));
    check();
    const iv = setInterval(check, 700);
    // respond instantly to the maximize/restore click and to opens/closes
    window.addEventListener('click', check);
    window.addEventListener('atharv-os:open', check);
    return () => { clearInterval(iv); window.removeEventListener('click', check); window.removeEventListener('atharv-os:open', check); };
  }, [phase]);

  /* ---- Pet handler (click = he licks the screen) ---- */
  const handlePet = (e) => {
    if (e) { e.stopPropagation(); e.preventDefault(); }
    if (phase !== 'desktop') return;
    if (tourRef.current.running) { stopTour(); showMessage('Okay, tour over — explore on your own! 🏔', 3500, true); return; }
    if (poseRef.current === 'sleep') { wake(); return; }
    if (window.sfx) window.sfx.bork();
    resetIdle();
    const newStreak = petStreak + 1;
    setPetStreak(newStreak);
    setTimeout(() => setPetStreak(s => Math.max(0, s - 1)), 2400);

    const newLife = petLifetime + 1;
    setPetLifetime(newLife);
    try { localStorage.setItem('atharvos.bevel.pets', String(newLife)); } catch {}

    if (newStreak >= 5) {
      play('excited');
      setPetStreak(0);
      showMessage('<i>WOOF WOOF WOOF.</i> okay okay I love you too.', 4500, true);
    } else if (newLife === 10) {
      play('dig-success');
      showMessage("You're his favourite visitor. <i>I dug this up for you.</i>", 6000, true);
    } else {
      play('lick');
      const licks = ['<i>*licks screen*</i>', '<i>woof!</i>', '...you taste like pixels.', '<i>wag wag.</i>', '<i>Hii.</i>'];
      showMessage(licks[Math.floor(Math.random() * licks.length)], 3500, true);
    }
  };

  // Expose pet trigger globally so desktop icon / events can pet Rover
  React.useEffect(() => {
    window.__atharvPetTrigger = () => handlePet();
    return () => { if (window.__atharvPetTrigger === handlePet) delete window.__atharvPetTrigger; };
  });

  /* ---- Right-click menu: tricks & controls ---- */
  const onContextMenu = (e) => {
    e.preventDefault();
    e.stopPropagation();
    setCtx({ x: Math.min(e.clientX, window.innerWidth - 180), y: Math.min(e.clientY, window.innerHeight - 200) });
  };
  const menuAction = (fn) => () => { setCtx(null); fn(); };
  const doTrick = () => {
    const t = ROVER_TRICKS[Math.floor(Math.random() * ROVER_TRICKS.length)];
    play(t);
    if (window.sfx) window.sfx.bork();
    const lines = {
      chef: 'Tonight: kibble, <i>deconstructed.</i>', football: 'GOOOAL. <i>woof.</i>',
      moviestar: 'Paparazzi, please.', dab: '<i>*dabs*</i>',
      'dig-success': 'Found it! Whatever it is.', excited: '<i>WOOF WOOF.</i>',
    };
    showMessage(lines[t] || '<i>Woof!</i>', 4500, true);
  };
  const goSleep = () => {
    manualSleepRef.current = true;
    clearTimeout(idleTimer.current);
    clearTimeout(sleepTimer.current);
    clearTimeout(actionTimer.current);
    setPose('sleep');
    setOneShot(null);
    setMessage(null);
  };
  const hideRover = () => {
    play('leave');
    showMessage('Okay. Type <b>rover</b> in the Run box to call me back.', 4000, true);
    setTimeout(() => setHidden(true), ROVER_ANIMS.leave.ms + 400);
  };

  /* ---- Guided tour: Rover narrates + opens key windows. Cancel by clicking
         him, pressing Esc, or opening/closing anything yourself. ---- */
  const tourRef = React.useRef({ timers: [], running: false });
  const stopTour = () => { tourRef.current.running = false; tourRef.current.timers.forEach(clearTimeout); tourRef.current.timers = []; };
  const runTour = () => {
    stopTour();
    manualSleepRef.current = false;
    if (poseRef.current === 'sleep') setPose('sit');
    tourRef.current.running = true;
    const open = (launch) => { try { window.dispatchEvent(new CustomEvent('atharv-os:launch', { detail: launch })); } catch (e) {} };
    // [message, animation, launch(optional), duration-before-next]
    const steps = [
      ['<b>Welcome!</b> I\'m Rover — let me show you around. 🐾', 'excited', null, 3200],
      ['First, <b>who Atharv is.</b>', 'sniff', { app: 'about' }, 4200],
      ['His <b>projects</b> live in My Computer — flagships first.', 'dig', { app: 'mycomputer' }, 4600],
      ['These three are <b>live in production</b> right now — see for yourself.', 'newspaper', { app: 'systems' }, 4800],
      ['He\'s <b>open to work</b> — this one matters.', 'newspaper', { app: 'hiring' }, 4600],
      ['And you can just <b>chat with the AI him</b> — it actually answers.', 'excited', { app: 'chat' }, 4200],
      ['That\'s the tour! Poke around — every icon opens something real. 🏔', 'lick', null, 4000],
    ];
    let t = 0;
    steps.forEach(([msg, anim, launch, dur]) => {
      tourRef.current.timers.push(setTimeout(() => {
        if (!tourRef.current.running) return;
        play(anim);
        showMessage(msg, dur + 400, true);
        if (launch) open(launch);
      }, t));
      t += dur;
    });
    tourRef.current.timers.push(setTimeout(() => { tourRef.current.running = false; }, t));
  };
  React.useEffect(() => stopTour, []);

  /* ---- Keyboard accessibility ---- */
  const onKeyDown = (e) => {
    if (e.key === 'Enter' || e.key === ' ') { handlePet(e); }
    else if (e.key === 'Escape') { setMessage(null); setCtx(null); stopTour(); }
  };

  if (!visible || hidden || covered || phase !== 'desktop') return null;

  const anim = oneShot || (pose === 'sleep' ? 'sleep' : 'idle');

  return (
    <>
      <div
        className={[
          'bevel', 'rover',
          `bevel-${corner}`,
          `bevel-pose-${pose}`,
          mpPlaying && pose !== 'sleep' && !oneShot ? 'bevel-music' : '',
        ].filter(Boolean).join(' ')}
        onClick={handlePet}
        onContextMenu={onContextMenu}
        onKeyDown={onKeyDown}
        role="button"
        tabIndex={0}
        aria-label="Rover, your guide (yes, the Windows XP one). Press Enter to pet, Shift+F10 for tricks."
        title="Rover — right-click for tricks"
      >
        <div className="bevel-frame">
          <RoverSprite anim={anim} playId={playId}/>
          {message && <BevelBubble message={message} corner={corner}/>}
        </div>
        {/* SR-only live announce */}
        <div className="bevel-sr" role="status" aria-live="polite">
          {message ? message.replace(/<[^>]+>/g, '') : ''}
        </div>
      </div>
      {ctx && (
        <div className="tray-ctx win raised" style={{ left: ctx.x, top: ctx.y, position: 'fixed', zIndex: 250000 }}
          onMouseLeave={() => setCtx(null)}>
          <div className="tray-ctx-item" onClick={menuAction(runTour)}>🐾 Take the tour</div>
          <div className="tray-ctx-item" onClick={menuAction(doTrick)}>Do a trick</div>
          <div className="tray-ctx-item" onClick={menuAction(() => handlePet())}>Pet Rover</div>
          <div className="tray-ctx-item" onClick={menuAction(() => { play('photo'); showMessage('<i>*poses*</i>', 3000, true); })}>Take his picture</div>
          <div className="tray-ctx-sep"/>
          <div className="tray-ctx-item" onClick={menuAction(pose === 'sleep' ? wake : goSleep)}>{pose === 'sleep' ? 'Wake up' : 'Go to sleep'}</div>
          <div className="tray-ctx-item" onClick={menuAction(hideRover)}>Hide Rover</div>
        </div>
      )}
    </>
  );
}

// Export to window scope for cross-file use (name kept for app.jsx wiring)
Object.assign(window, { BevelMascot });
