/* Calculator, WordPad, Solitaire, Sound Recorder, Microsoft Bob, Screensaver, ContextMenu */

/* ============== Calculator ============== */
function Calculator() {
  const [display, setDisplay] = React.useState("0");
  const [acc, setAcc] = React.useState(null);
  const [op, setOp] = React.useState(null);
  const [resetNext, setResetNext] = React.useState(false);
  const [mem, setMem] = React.useState(0);

  const press = (key) => {
    if (window.Sounds) window.Sounds.click();
    if (/^[0-9]$/.test(key)) {
      setDisplay(d => (resetNext || d === "0") ? key : d + key);
      setResetNext(false);
    } else if (key === ".") {
      setDisplay(d => d.includes(".") ? d : d + ".");
      setResetNext(false);
    } else if (["+", "-", "*", "/"].includes(key)) {
      if (acc != null && op && !resetNext) doEquals();
      else setAcc(parseFloat(display));
      setOp(key);
      setResetNext(true);
    } else if (key === "=") {
      doEquals();
    } else if (key === "C") {
      setDisplay("0"); setAcc(null); setOp(null); setResetNext(false);
    } else if (key === "CE") {
      setDisplay("0");
    } else if (key === "±") {
      setDisplay(d => d.startsWith("-") ? d.slice(1) : (d === "0" ? d : "-" + d));
    } else if (key === "√") {
      const v = parseFloat(display);
      setDisplay(v < 0 ? "Erreur" : String(Math.sqrt(v)));
      setResetNext(true);
    } else if (key === "1/x") {
      const v = parseFloat(display);
      setDisplay(v === 0 ? "Erreur" : String(1 / v));
      setResetNext(true);
    } else if (key === "MC") setMem(0);
    else if (key === "MR") { setDisplay(String(mem)); setResetNext(true); }
    else if (key === "MS") setMem(parseFloat(display));
    else if (key === "M+") setMem(m => m + parseFloat(display));
  };

  const doEquals = () => {
    if (acc == null || op == null) return;
    const b = parseFloat(display);
    let r = 0;
    if (op === "+") r = acc + b;
    if (op === "-") r = acc - b;
    if (op === "*") r = acc * b;
    if (op === "/") r = b === 0 ? NaN : acc / b;
    setDisplay(Number.isFinite(r) ? String(parseFloat(r.toPrecision(12))) : "Erreur");
    setAcc(null); setOp(null); setResetNext(true);
  };

  return (
    <div className="calc">
      <div className="calc-display">{display}</div>
      <div className="calc-mem-row">
        <button className="calc-mem-btn" onClick={() => press("MC")}>MC</button>
        <button className="calc-mem-btn" onClick={() => press("MR")}>MR</button>
        <button className="calc-mem-btn" onClick={() => press("MS")}>MS</button>
        <button className="calc-mem-btn" onClick={() => press("M+")}>M+</button>
      </div>
      <div className="calc-grid">
        {[
          ['CE','C','±','√'],
          ['7','8','9','/'],
          ['4','5','6','*'],
          ['1','2','3','-'],
          ['0','.','=','+'],
        ].map((row, ri) => row.map((k, ci) => (
          <button
            key={`${ri}-${ci}`}
            className={`calc-btn ${['+','-','*','/','='].includes(k) ? 'calc-op' : ''} ${['CE','C','±','√'].includes(k) ? 'calc-fn' : ''}`}
            onClick={() => press(k)}
          >{k}</button>
        )))}
        <button className="calc-btn calc-fn" onClick={() => press("1/x")} style={{ gridColumn: '1 / 5', marginTop: 4 }}>1/x</button>
      </div>
    </div>
  );
}


/* ============== WordPad ============== */
function WordPad() {
  const [bold, setBold] = React.useState(false);
  const [italic, setItalic] = React.useState(false);
  const [underline, setUnderline] = React.useState(false);
  const [size, setSize] = React.useState(12);
  const [color, setColor] = React.useState("#000000");
  const ed = React.useRef(null);
  const cmd = (c, val) => { document.execCommand(c, false, val); ed.current && ed.current.focus(); };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
      <WindowMenu items={["Fichier", "Edition", "Affichage", "Insertion", "Format", "Aide"]} />
      <div className="wordpad-toolbar">
        <select value={size} onChange={(e) => { setSize(+e.target.value); cmd('fontSize', Math.min(7, Math.max(1, Math.round(+e.target.value/4)))); }}>
          {[8,10,12,14,18,24,36].map(s => <option key={s} value={s}>{s}</option>)}
        </select>
        <button className={`wp-btn ${bold ? 'active' : ''}`} onClick={() => { setBold(b => !b); cmd('bold'); }}><b>G</b></button>
        <button className={`wp-btn ${italic ? 'active' : ''}`} onClick={() => { setItalic(b => !b); cmd('italic'); }}><i>I</i></button>
        <button className={`wp-btn ${underline ? 'active' : ''}`} onClick={() => { setUnderline(b => !b); cmd('underline'); }}><u>S</u></button>
        <input type="color" value={color} onChange={(e) => { setColor(e.target.value); cmd('foreColor', e.target.value); }} title="Couleur du texte" />
        <span className="wp-sep"></span>
        <button className="wp-btn" onClick={() => cmd('justifyLeft')}>⇤</button>
        <button className="wp-btn" onClick={() => cmd('justifyCenter')}>≡</button>
        <button className="wp-btn" onClick={() => cmd('justifyRight')}>⇥</button>
      </div>
      <div
        ref={ed}
        className="wordpad-doc"
        contentEditable
        suppressContentEditableWarning
        dangerouslySetInnerHTML={{ __html: `<div style="font-family: 'Times New Roman', serif; font-size: ${size}pt;">
          <h2 style="font-family: 'Times New Roman', serif;">Document.rtf</h2>
          <p>Tapez votre <b>texte enrichi</b> ici. Utilisez la barre d'outils pour formater.</p>
          <p style="color: #800080;"><i>Microsoft WordPad</i> est l'éditeur de texte enrichi inclus avec Windows&nbsp;98.</p>
        </div>` }}
      />
      <div className="wordpad-status">
        <span>Pour obtenir l'Aide, appuyez sur F1.</span>
        <span></span>
      </div>
    </div>
  );
}


/* ============== Solitaire (Klondike, draw 1) ============== */
function Solitaire() {
  const SUITS = ['♠', '♥', '♦', '♣'];
  const isRed = (s) => s === '♥' || s === '♦';

  const newDeck = () => {
    const cards = [];
    for (const s of SUITS) for (let r = 1; r <= 13; r++) cards.push({ s, r, faceUp: false });
    for (let i = cards.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1));
      [cards[i], cards[j]] = [cards[j], cards[i]];
    }
    return cards;
  };

  const newGame = () => {
    const deck = newDeck();
    const tab = Array(7).fill(0).map(() => []);
    for (let i = 0; i < 7; i++) {
      for (let j = i; j < 7; j++) {
        const c = deck.pop();
        if (j === i) c.faceUp = true;
        tab[j].push(c);
      }
    }
    return { tab, stock: deck, waste: [], found: [[], [], [], []], moves: 0, won: false };
  };

  const [state, setState] = React.useState(newGame);
  const [sel, setSel] = React.useState(null); // {from, idx, count}

  const top = (pile) => pile[pile.length - 1];
  const rankStr = (r) => r === 1 ? 'A' : r === 11 ? 'J' : r === 12 ? 'Q' : r === 13 ? 'K' : String(r);

  const canDropFound = (card, found) => {
    const t = top(found);
    if (!t) return card.r === 1;
    return t.s === card.s && card.r === t.r + 1;
  };
  const canDropTab = (card, pile) => {
    const t = top(pile);
    if (!t) return card.r === 13;
    return isRed(card.s) !== isRed(t.s) && card.r === t.r - 1;
  };

  const doMove = (mut) => {
    setState(prev => {
      const ns = JSON.parse(JSON.stringify(prev));
      mut(ns);
      // flip uncovered tableau tops
      ns.tab.forEach(p => { if (p.length && !top(p).faceUp) top(p).faceUp = true; });
      ns.moves++;
      // check win
      ns.won = ns.found.every(f => f.length === 13);
      return ns;
    });
    setSel(null);
    if (window.Sounds) window.Sounds.click();
  };

  const drawStock = () => {
    if (state.stock.length === 0 && state.waste.length === 0) return;
    doMove(ns => {
      if (ns.stock.length === 0) {
        ns.stock = ns.waste.reverse().map(c => ({ ...c, faceUp: false }));
        ns.waste = [];
      } else {
        const c = ns.stock.pop();
        c.faceUp = true;
        ns.waste.push(c);
      }
    });
  };

  const clickCard = (from, idx) => {
    if (from === 'stock') return drawStock();
    if (!sel) {
      let pile, card;
      if (from.kind === 'tab') { pile = state.tab[from.i]; card = pile[idx]; }
      else if (from.kind === 'waste') { pile = state.waste; card = pile[pile.length - 1]; }
      else if (from.kind === 'found') { pile = state.found[from.i]; card = pile[pile.length - 1]; }
      if (!card || !card.faceUp) return;
      setSel({ from, idx });
      return;
    }
    // attempt move sel → here
    const src = sel.from;
    const srcPile = src.kind === 'tab' ? state.tab[src.i] : src.kind === 'waste' ? state.waste : state.found[src.i];
    const movingCards = src.kind === 'tab' ? srcPile.slice(sel.idx) : [srcPile[srcPile.length - 1]];
    const first = movingCards[0];
    let ok = false;
    if (from.kind === 'found' && movingCards.length === 1) ok = canDropFound(first, state.found[from.i]);
    else if (from.kind === 'tab') ok = canDropTab(first, state.tab[from.i]);
    if (!ok) { setSel(null); return; }
    doMove(ns => {
      const sp = src.kind === 'tab' ? ns.tab[src.i] : src.kind === 'waste' ? ns.waste : ns.found[src.i];
      const dp = from.kind === 'tab' ? ns.tab[from.i] : ns.found[from.i];
      const cards = src.kind === 'tab' ? sp.splice(sel.idx) : [sp.pop()];
      dp.push(...cards);
    });
  };

  const dblClick = (from, idx) => {
    // auto-send to a foundation if possible
    let card;
    if (from.kind === 'tab') { const p = state.tab[from.i]; if (idx !== p.length - 1) return; card = p[idx]; }
    else if (from.kind === 'waste') card = state.waste[state.waste.length - 1];
    if (!card || !card.faceUp) return;
    for (let i = 0; i < 4; i++) {
      if (canDropFound(card, state.found[i])) {
        doMove(ns => {
          if (from.kind === 'tab') ns.tab[from.i].pop();
          else ns.waste.pop();
          ns.found[i].push(card);
        });
        return;
      }
    }
  };

  const Card = ({ c, faceDown, selected, onClick, onDouble, style }) => (
    <div
      className={`sol-card ${selected ? 'selected' : ''} ${faceDown || !c.faceUp ? 'down' : ''}`}
      style={style}
      onClick={onClick}
      onDoubleClick={onDouble}
    >
      {(!faceDown && c.faceUp) && (
        <div className={`sol-face ${isRed(c.s) ? 'red' : 'black'}`}>
          <div className="sol-corner">
            <div>{rankStr(c.r)}</div>
            <div>{c.s}</div>
          </div>
          <div className="sol-center">{c.s}</div>
        </div>
      )}
    </div>
  );

  return (
    <div className="solitaire">
      <div className="sol-top">
        <div className="sol-stock-area">
          <div className="sol-pile" onClick={drawStock} title="Pioche">
            {state.stock.length > 0 ? <div className="sol-card down"></div> : <div className="sol-empty">↺</div>}
          </div>
          <div className="sol-pile">
            {state.waste.length > 0 ? (
              <Card
                c={state.waste[state.waste.length - 1]}
                selected={sel && sel.from.kind === 'waste'}
                onClick={() => clickCard({ kind: 'waste' }, state.waste.length - 1)}
                onDouble={() => dblClick({ kind: 'waste' })}
              />
            ) : <div className="sol-empty"></div>}
          </div>
        </div>
        <div className="sol-foundations">
          {state.found.map((f, i) => (
            <div className="sol-pile" key={i} onClick={() => sel ? clickCard({ kind: 'found', i }) : null}>
              {f.length > 0 ? (
                <Card c={f[f.length - 1]} onClick={() => sel && clickCard({ kind: 'found', i })} />
              ) : <div className="sol-empty">{SUITS[i]}</div>}
            </div>
          ))}
        </div>
      </div>
      <div className="sol-tableau">
        {state.tab.map((pile, i) => (
          <div className="sol-tab-col" key={i} onClick={() => sel && pile.length === 0 && clickCard({ kind: 'tab', i }, 0)}>
            {pile.length === 0 && <div className="sol-empty"></div>}
            {pile.map((c, j) => (
              <Card
                key={j}
                c={c}
                selected={sel && sel.from.kind === 'tab' && sel.from.i === i && j >= sel.idx}
                onClick={() => clickCard({ kind: 'tab', i }, j)}
                onDouble={() => dblClick({ kind: 'tab', i }, j)}
                style={{ marginTop: j === 0 ? 0 : (c.faceUp ? -56 : -64) }}
              />
            ))}
          </div>
        ))}
      </div>
      <div className="sol-toolbar">
        <button className="btn" onClick={() => setState(newGame())}>Nouveau</button>
        <span>Coups : {state.moves}</span>
        {state.won && <span style={{ color: 'gold', fontWeight: 'bold' }}>🏆 Vous avez gagné !</span>}
      </div>
    </div>
  );
}


/* ============== Sound Recorder ============== */
function SoundRecorder() {
  const [recording, setRecording] = React.useState(false);
  const [time, setTime] = React.useState(0);
  const [wave, setWave] = React.useState(Array(48).fill(0));
  React.useEffect(() => {
    if (!recording) return;
    const id = setInterval(() => {
      setTime(t => t + 0.1);
      setWave(prev => {
        const next = prev.slice(1);
        next.push(Math.random() * 2 - 1);
        return next;
      });
    }, 100);
    return () => clearInterval(id);
  }, [recording]);
  return (
    <div className="recorder">
      <div className="recorder-display">
        <div className="recorder-time">Position : {time.toFixed(2)} sec.</div>
        <div className="recorder-time">Longueur : 60.00 sec.</div>
        <svg viewBox="0 0 240 60" className="recorder-wave">
          <line x1="0" y1="30" x2="240" y2="30" stroke="#666" strokeWidth="0.5"/>
          {wave.map((v, i) => (
            <line key={i} x1={i*5} y1={30 - v*22} x2={i*5} y2={30 + v*22} stroke="#000" strokeWidth="1.5"/>
          ))}
        </svg>
      </div>
      <div className="recorder-controls">
        <button className="rec-btn" onClick={() => { setRecording(false); setTime(0); }} title="Retour au début">⏮</button>
        <button className="rec-btn" onClick={() => setRecording(false)} title="Fin">⏭</button>
        <button className="rec-btn" onClick={() => setRecording(false)} title="Lire">▶</button>
        <button className="rec-btn" onClick={() => setRecording(false)} title="Arrêter">⏹</button>
        <button className={`rec-btn rec-record ${recording ? 'on' : ''}`} onClick={() => setRecording(r => !r)} title="Enregistrer">●</button>
      </div>
    </div>
  );
}


/* ============== Microsoft Bob (Easter egg) ============== */
function MicrosoftBob() {
  return (
    <div className="bob">
      <div className="bob-house">
        <div className="bob-roof"></div>
        <div className="bob-walls">
          <div className="bob-window"></div>
          <div className="bob-door"></div>
          <div className="bob-window"></div>
        </div>
        <div className="bob-lawn"></div>
        <div className="bob-sun">☀</div>
        <div className="bob-cloud" style={{ left: 20 }}>☁</div>
        <div className="bob-cloud" style={{ left: 220 }}>☁</div>
        <div className="bob-pet">🐶</div>
      </div>
      <div className="bob-msg">
        Bienvenue chez Microsoft Bob ! Cliquez sur la porte pour entrer dans votre maison virtuelle.
        <br/><i>(produit Microsoft 1995-1996, abandonné après 6 mois)</i>
      </div>
    </div>
  );
}


/* ============== Screensaver: Mystify ============== */
function MystifyScreensaver({ onDismiss }) {
  const canvasRef = React.useRef(null);
  React.useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const dpr = window.devicePixelRatio || 1;
    canvas.width = window.innerWidth * dpr;
    canvas.height = window.innerHeight * dpr;
    canvas.style.width = window.innerWidth + 'px';
    canvas.style.height = window.innerHeight + 'px';
    const ctx = canvas.getContext('2d');
    ctx.scale(dpr, dpr);
    const W = window.innerWidth, H = window.innerHeight;
    const polys = [
      { pts: Array(4).fill(0).map(() => ({ x: Math.random()*W, y: Math.random()*H, vx: (Math.random()-0.5)*4, vy: (Math.random()-0.5)*4 })), trail: [], hue: 290 },
      { pts: Array(4).fill(0).map(() => ({ x: Math.random()*W, y: Math.random()*H, vx: (Math.random()-0.5)*4, vy: (Math.random()-0.5)*4 })), trail: [], hue: 200 },
    ];
    let raf;
    const tick = () => {
      ctx.fillStyle = 'rgba(0,0,0,0.18)';
      ctx.fillRect(0, 0, W, H);
      polys.forEach(p => {
        p.pts.forEach(pt => {
          pt.x += pt.vx; pt.y += pt.vy;
          if (pt.x < 0 || pt.x > W) pt.vx *= -1;
          if (pt.y < 0 || pt.y > H) pt.vy *= -1;
        });
        p.trail.push(p.pts.map(pt => ({ x: pt.x, y: pt.y })));
        if (p.trail.length > 20) p.trail.shift();
        p.trail.forEach((shape, i) => {
          ctx.strokeStyle = `hsl(${p.hue}, 100%, ${30 + (i / p.trail.length) * 50}%)`;
          ctx.lineWidth = 1.5;
          ctx.beginPath();
          ctx.moveTo(shape[0].x, shape[0].y);
          for (let k = 1; k < shape.length; k++) ctx.lineTo(shape[k].x, shape[k].y);
          ctx.closePath();
          ctx.stroke();
        });
      });
      raf = requestAnimationFrame(tick);
    };
    tick();
    return () => cancelAnimationFrame(raf);
  }, []);

  React.useEffect(() => {
    const dismiss = () => onDismiss();
    window.addEventListener('keydown', dismiss);
    window.addEventListener('mousedown', dismiss);
    window.addEventListener('mousemove', dismiss);
    return () => {
      window.removeEventListener('keydown', dismiss);
      window.removeEventListener('mousedown', dismiss);
      window.removeEventListener('mousemove', dismiss);
    };
  }, [onDismiss]);

  return <canvas ref={canvasRef} className="screensaver"/>;
}


/* ============== Desktop context menu ============== */
function ContextMenu({ x, y, items, onClose }) {
  React.useEffect(() => {
    const onDown = () => onClose();
    setTimeout(() => window.addEventListener('mousedown', onDown), 0);
    return () => window.removeEventListener('mousedown', onDown);
  }, [onClose]);
  return (
    <div className="ctx-menu" style={{ left: x, top: y }} onMouseDown={(e) => e.stopPropagation()}>
      {items.map((it, i) => it.sep ? (
        <div key={i} className="ctx-sep"></div>
      ) : (
        <div key={i} className={`ctx-item ${it.disabled ? 'disabled' : ''}`} onClick={() => { if (!it.disabled) { it.action && it.action(); onClose(); } }}>
          <span className="ctx-label">{it.label}</span>
          {it.right && <span className="ctx-right">{it.right}</span>}
        </div>
      ))}
    </div>
  );
}

window.Calculator = Calculator;
window.WordPad = WordPad;
window.Solitaire = Solitaire;
window.SoundRecorder = SoundRecorder;
window.MicrosoftBob = MicrosoftBob;
window.MystifyScreensaver = MystifyScreensaver;
window.ContextMenu = ContextMenu;
