/* global React, Icon, IconBtn, db */
const { useState, useEffect, useCallback, useMemo, useRef } = React;

// ============================================================
// Solitaire — Klondike, draw-one.
// Click a card to select it; click a destination pile to move.
// Double-click sends a card to its foundation if legal.
// Click the stock to draw the next card to the waste; if the
// stock is empty, click again to recycle the waste.
// ============================================================

const SUITS = ['S', 'H', 'D', 'C'];   // Spades, Hearts, Diamonds, Clubs
const SUIT_SYMBOL = { S: '♠', H: '♥', D: '♦', C: '♣' };
const SUIT_COLOR  = { S: 'black', H: 'red', D: 'red', C: 'black' };
const RANK_LABEL  = ['', 'A','2','3','4','5','6','7','8','9','10','J','Q','K'];

function makeDeck() {
  const deck = [];
  let id = 1;
  for (const s of SUITS) for (let r = 1; r <= 13; r++) deck.push({ id: id++, suit: s, rank: r, faceUp: false });
  return deck;
}
function shuffleDeck(deck) {
  const out = deck.slice();
  for (let i = out.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [out[i], out[j]] = [out[j], out[i]];
  }
  return out;
}

function dealNewGame() {
  const deck = shuffleDeck(makeDeck());
  const tableau = [[], [], [], [], [], [], []];
  let idx = 0;
  for (let pile = 0; pile < 7; pile++) {
    for (let row = pile; row < 7; row++) {
      tableau[row].push(deck[idx++]);
    }
  }
  // Flip the top card of each tableau pile face up
  for (const pile of tableau) if (pile.length > 0) pile[pile.length - 1].faceUp = true;
  const stock = deck.slice(idx).map(c => ({ ...c, faceUp: false }));
  return {
    stock,
    waste: [],
    foundations: [[], [], [], []],
    tableau,
    moves: 0,
    startedAt: Date.now(),
  };
}

// ---- Move legality ----
function canPlaceOnFoundation(card, foundation) {
  if (foundation.length === 0) return card.rank === 1;
  const top = foundation[foundation.length - 1];
  return top.suit === card.suit && card.rank === top.rank + 1;
}
function canPlaceOnTableau(card, pile) {
  if (pile.length === 0) return card.rank === 13;
  const top = pile[pile.length - 1];
  if (!top.faceUp) return false;
  return SUIT_COLOR[top.suit] !== SUIT_COLOR[card.suit] && card.rank === top.rank - 1;
}

function SolitaireTool() {
  const [state, setState] = useState(null);
  const [selected, setSelected] = useState(null); // { src: 'waste'|'tab'|'found', idx, cardIdx }
  const [now, setNow] = useState(Date.now());
  const [history, setHistory] = useState([]); // for undo

  // Load saved game
  useEffect(() => {
    db.kv.get('solitaireState').then(rec => {
      if (rec?.v) setState(rec.v);
      else setState(dealNewGame());
    });
  }, []);
  useEffect(() => {
    if (state) db.kv.put({ k: 'solitaireState', v: state });
  }, [state]);

  useEffect(() => {
    if (!state || won(state)) return;
    const id = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(id);
  }, [state]);

  const newGame = () => {
    setState(dealNewGame());
    setSelected(null);
    setHistory([]);
  };

  const pushHistory = (snap) => setHistory(h => [...h.slice(-50), snap]);
  const undo = () => {
    if (history.length === 0) return;
    setState(history[history.length - 1]);
    setHistory(h => h.slice(0, -1));
    setSelected(null);
  };

  // ---- Stock click ----
  const onStockClick = () => {
    if (!state) return;
    pushHistory(structuredClone(state));
    if (state.stock.length === 0) {
      // Recycle waste back into stock (face-down, reversed order)
      const recycled = state.waste.slice().reverse().map(c => ({ ...c, faceUp: false }));
      setState({ ...state, stock: recycled, waste: [], moves: state.moves + 1 });
    } else {
      const next = { ...state };
      const card = { ...next.stock[next.stock.length - 1], faceUp: true };
      next.stock = next.stock.slice(0, -1);
      next.waste = [...next.waste, card];
      next.moves++;
      setState(next);
    }
    setSelected(null);
  };

  // ---- Card / pile click handling ----
  const onCardClick = (src, pileIdx, cardIdx) => {
    if (!state) return;
    const pile = getPile(state, src, pileIdx);
    const card = pile[cardIdx];
    if (!card || !card.faceUp) return;
    // Can only select bottom range from cardIdx down to end of pile, but only
    // from tableau (foundation only moves the top card). Waste: top card only.
    if (src === 'waste' && cardIdx !== pile.length - 1) return;
    if (src === 'found' && cardIdx !== pile.length - 1) return;
    if (src === 'tab') {
      // Selecting a stack from cardIdx to end. All must be face-up.
      for (let i = cardIdx; i < pile.length; i++) if (!pile[i].faceUp) return;
    }
    if (selected && selected.src === src && selected.pileIdx === pileIdx && selected.cardIdx === cardIdx) {
      setSelected(null);
    } else {
      setSelected({ src, pileIdx, cardIdx });
    }
  };

  const onPileClick = (dstSrc, dstIdx) => {
    if (!state || !selected) return;
    const next = structuredClone(state);
    const srcPile = getPile(next, selected.src, selected.pileIdx);
    const cardsBeingMoved = srcPile.slice(selected.cardIdx);
    const dstPile = getPile(next, dstSrc, dstIdx);

    // Validate
    if (dstSrc === 'found') {
      if (cardsBeingMoved.length !== 1) return;
      if (!canPlaceOnFoundation(cardsBeingMoved[0], dstPile)) return;
    } else if (dstSrc === 'tab') {
      if (!canPlaceOnTableau(cardsBeingMoved[0], dstPile)) return;
    } else {
      return;
    }
    pushHistory(structuredClone(state));
    // Move
    dstPile.push(...cardsBeingMoved);
    srcPile.length = selected.cardIdx;
    // Auto-flip uncovered tableau card
    if (selected.src === 'tab' && srcPile.length > 0 && !srcPile[srcPile.length - 1].faceUp) {
      srcPile[srcPile.length - 1].faceUp = true;
    }
    next.moves++;
    setState(next);
    setSelected(null);
  };

  const tryAutoToFoundation = (src, pileIdx, cardIdx) => {
    if (!state) return false;
    const pile = getPile(state, src, pileIdx);
    if (cardIdx !== pile.length - 1) return false;
    const card = pile[cardIdx];
    if (!card || !card.faceUp) return false;
    // Find a foundation that can accept it
    for (let fi = 0; fi < 4; fi++) {
      if (canPlaceOnFoundation(card, state.foundations[fi])) {
        const next = structuredClone(state);
        const srcPile = getPile(next, src, pileIdx);
        const moved = srcPile.pop();
        next.foundations[fi].push(moved);
        if (src === 'tab' && srcPile.length > 0 && !srcPile[srcPile.length - 1].faceUp) {
          srcPile[srcPile.length - 1].faceUp = true;
        }
        next.moves++;
        pushHistory(structuredClone(state));
        setState(next);
        setSelected(null);
        return true;
      }
    }
    return false;
  };

  if (!state) return <div className="sol-tool sol-loading" />;

  const elapsed = now - state.startedAt;
  const isWon = won(state);

  return (
    <div className="sol-tool">
      <header className="sol-head">
        <div>
          <h1>Solitaire</h1>
          <p>Klondike, draw one. Click to select, click a pile to move. Double-click sends to foundation.</p>
        </div>
        <div className="sol-status">
          <span><Icon name="timer" />{formatSolTime(elapsed)}</span>
          <span><Icon name="moving" />{state.moves} moves</span>
          {isWon && <span className="sol-win"><Icon name="emoji_events" />You won!</span>}
          <button className="lh-btn ghost" onClick={undo} disabled={history.length === 0}>
            <Icon name="undo" />Undo
          </button>
          <button className="lh-btn primary" onClick={newGame}>
            <Icon name="refresh" />New deal
          </button>
        </div>
      </header>

      <div className="sol-top">
        {/* Stock + waste */}
        <div className="sol-top-left">
          <button className="sol-pile sol-stock" onClick={onStockClick} title="Draw">
            {state.stock.length > 0 ? (
              <div className="sol-card sol-card-back" />
            ) : (
              <div className="sol-pile-empty sol-stock-empty"><Icon name="refresh" /></div>
            )}
          </button>
          <div className="sol-pile sol-waste">
            {state.waste.length === 0 ? (
              <div className="sol-pile-empty" />
            ) : state.waste.slice(-3).map((c, i, arr) => (
              <SolCard
                key={c.id}
                card={c}
                style={{ top: 0, left: i * 14 }}
                selected={selected?.src === 'waste' && i === arr.length - 1}
                onClick={() => onCardClick('waste', 0, state.waste.length - 1)}
                onDoubleClick={() => i === arr.length - 1 && tryAutoToFoundation('waste', 0, state.waste.length - 1)}
              />
            ))}
          </div>
        </div>
        {/* Foundations */}
        <div className="sol-top-right">
          {state.foundations.map((pile, fi) => (
            <button
              key={fi}
              className={`sol-pile sol-found ${selected ? 'is-target' : ''}`}
              onClick={() => onPileClick('found', fi)}
            >
              {pile.length === 0 ? (
                <div className="sol-pile-empty"><span className="sol-found-letter">{['♠','♥','♦','♣'][fi]}</span></div>
              ) : (
                <SolCard
                  card={pile[pile.length - 1]}
                  selected={selected?.src === 'found' && selected.pileIdx === fi}
                  onClick={(e) => { e.stopPropagation(); onCardClick('found', fi, pile.length - 1); }}
                />
              )}
            </button>
          ))}
        </div>
      </div>

      {/* Tableau */}
      <div className="sol-tableau">
        {state.tableau.map((pile, ti) => (
          <div
            key={ti}
            className={`sol-tab-pile ${selected ? 'is-target' : ''}`}
            onClick={(e) => {
              // Only fire if clicked on the empty pile, not a card (cards stop propagation).
              if (e.target === e.currentTarget || e.target.classList.contains('sol-pile-empty')) {
                onPileClick('tab', ti);
              }
            }}
          >
            {pile.length === 0 ? (
              <div className="sol-pile-empty sol-tab-empty" />
            ) : pile.map((c, ci) => (
              <SolCard
                key={c.id}
                card={c}
                style={{ top: ci * 22 }}
                selected={selected?.src === 'tab' && selected.pileIdx === ti && ci >= selected.cardIdx}
                onClick={(e) => { e.stopPropagation(); onCardClick('tab', ti, ci); }}
                onDoubleClick={(e) => { e.stopPropagation(); if (ci === pile.length - 1) tryAutoToFoundation('tab', ti, ci); }}
              />
            ))}
          </div>
        ))}
      </div>
    </div>
  );
}

function getPile(state, src, idx) {
  if (src === 'waste') return state.waste;
  if (src === 'found') return state.foundations[idx];
  if (src === 'tab')   return state.tableau[idx];
  throw new Error('Unknown pile source: ' + src);
}

function won(state) {
  return state.foundations.every(p => p.length === 13);
}

function formatSolTime(ms) {
  const total = Math.floor(ms / 1000);
  const m = Math.floor(total / 60), s = total % 60;
  return `${m}:${String(s).padStart(2, '0')}`;
}

// ============================================================
// SolCard — visual card.
// ============================================================
function SolCard({ card, style, selected, onClick, onDoubleClick }) {
  if (!card) return null;
  if (!card.faceUp) {
    return <div className="sol-card sol-card-back" style={style} onClick={onClick} />;
  }
  return (
    <div
      className={`sol-card sol-card-face sol-card-${SUIT_COLOR[card.suit]} ${selected ? 'is-selected' : ''}`}
      style={style}
      onClick={onClick}
      onDoubleClick={onDoubleClick}
    >
      <div className="sol-card-corner top">
        <span className="sol-card-rank">{RANK_LABEL[card.rank]}</span>
        <span className="sol-card-suit">{SUIT_SYMBOL[card.suit]}</span>
      </div>
      <span className="sol-card-big">{SUIT_SYMBOL[card.suit]}</span>
      <div className="sol-card-corner bot">
        <span className="sol-card-rank">{RANK_LABEL[card.rank]}</span>
        <span className="sol-card-suit">{SUIT_SYMBOL[card.suit]}</span>
      </div>
    </div>
  );
}

window.SolitaireTool = SolitaireTool;
