// Activities part 1: Memory, Match, Order, Fill, Answer
// CreateJS used in Puzzle and Memory.

const { useState: useStateA, useEffect: useEffectA, useRef: useRefA, useMemo: useMemoA, useCallback: useCallbackA } = React;

// Helpers
function shuffle(arr) {
  const a = [...arr];
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}
function pickN(arr, n) { return shuffle(arr).slice(0, n); }
function range(n) { return Array.from({length:n}, (_,i)=>i); }

// =========================================================
// 1. MEMORIA — pairs of cards (operation ↔ result)
// =========================================================
function ActMemory({ theme, difficulty, onCorrect, onMistake, onFinish, data }) {
  const pairsCount = { facil: 4, media: 6, dificil: 8 }[difficulty] || 6;

  const cards = useMemoA(() => {
    if (Array.isArray(data?.pares) && data.pares.length) {
      const rawPairs = pickN(data.pares, Math.min(pairsCount, data.pares.length));
      const deck = [];
      rawPairs.forEach((p, i) => {
        const left = String(p?.concepto ?? '').trim();
        const right = String(p?.respuesta ?? '').trim();
        if (!left || !right) return;
        deck.push({ id: `e${i}`, pair: i, label: left });
        deck.push({ id: `r${i}`, pair: i, label: right });
      });
      if (deck.length >= 4) return shuffle(deck);
    }

    const ops = [];
    while (ops.length < pairsCount) {
      const a = 2 + Math.floor(Math.random()*9);
      const b = 2 + Math.floor(Math.random()*9);
      const op = Math.random() < 0.5 ? "+" : "×";
      const r = op === "+" ? a + b : a * b;
      const expr = `${a}${op}${b}`;
      if (!ops.some(o => o.r === r)) ops.push({ expr, r });
    }
    const deck = [];
    ops.forEach((o, i) => {
      deck.push({ id: `e${i}`, pair: i, label: o.expr });
      deck.push({ id: `r${i}`, pair: i, label: String(o.r) });
    });
    return shuffle(deck);
  }, [pairsCount, data]);

  const [flipped, setFlipped] = useStateA([]);
  const [matched, setMatched] = useStateA(new Set());
  const [mistakes, setMistakes] = useStateA(0);
  const lock = useRefA(false);

  useEffectA(() => {
    if (matched.size === cards.length && cards.length > 0) {
      const correct = cards.length / 2 - mistakes;
      setTimeout(() => onFinish(Math.max(1, correct), cards.length / 2), 800);
    }
  }, [matched, cards.length, mistakes, onFinish]);

  const click = (i) => {
    if (lock.current || flipped.includes(i) || matched.has(cards[i].id)) return;
    window.SFX && window.SFX.pickup();
    const next = [...flipped, i];
    setFlipped(next);
    if (next.length === 2) {
      lock.current = true;
      const [a, b] = next;
      if (cards[a].pair === cards[b].pair) {
        setTimeout(() => {
          setMatched(m => new Set([...m, cards[a].id, cards[b].id]));
          setFlipped([]);
          lock.current = false;
          onCorrect();
        }, 500);
      } else {
        setMistakes(m => m + 1);
        setTimeout(() => {
          setFlipped([]);
          lock.current = false;
          onMistake();
        }, 900);
      }
    }
  };

  const cols = pairsCount === 4 ? 4 : pairsCount === 6 ? 4 : 4;

  return (
    <div className="ma-memory">
      <div className="ma-instruction">Empareja cada operación con su resultado.</div>
      <div className="ma-memory-grid" style={{gridTemplateColumns: `repeat(${cols}, 1fr)`}}>
        {cards.map((c, i) => {
          const show = flipped.includes(i) || matched.has(c.id);
          const isMatched = matched.has(c.id);
          const labelText = String(c.label || '');
          const labelLen = labelText.length;
          const fontSizeStyle = labelLen > 24 ? 'calc(11px * var(--font-scale))' :
                                labelLen > 16 ? 'calc(14px * var(--font-scale))' :
                                labelLen > 10 ? 'calc(18px * var(--font-scale))' :
                                labelLen > 6  ? 'calc(22px * var(--font-scale))' :
                                undefined;
          return (
            <button key={c.id+i} className={`ma-card ${show?"ma-card-show":""} ${isMatched?"ma-card-matched":""}`}
              onClick={() => click(i)} disabled={isMatched}>
              <div className="ma-card-inner">
                <div className="ma-card-front">?</div>
                <div className="ma-card-back" style={{ fontSize: fontSizeStyle }}>{c.label}</div>
              </div>
            </button>
          );
        })}
      </div>
    </div>
  );
}

// =========================================================
// 2. ASOCIACIÓN — match operations to results (drag lines)
// =========================================================
function ActMatch({ theme, difficulty, onCorrect, onMistake, onFinish, data }) {
  const count = { facil: 4, media: 5, dificil: 6 }[difficulty] || 5;

  const pairs = useMemoA(() => {
    if (Array.isArray(data?.pares) && data.pares.length) {
      return pickN(data.pares, Math.min(count, data.pares.length)).map((p, idx) => ({
        expr: String(p?.concepto ?? ''),
        r: String(p?.respuesta ?? ''),
        id: idx,
      })).filter((p) => p.expr && p.r);
    }

    const out = [];
    while (out.length < count) {
      const a = 2 + Math.floor(Math.random()*8);
      const b = 2 + Math.floor(Math.random()*8);
      const op = ["+","-","×"][Math.floor(Math.random()*3)];
      let r;
      if (op === "+") r = a + b;
      else if (op === "-") r = Math.max(a,b) - Math.min(a,b);
      else r = a * b;
      const expr = op === "-" ? `${Math.max(a,b)}-${Math.min(a,b)}` : `${a}${op}${b}`;
      if (!out.some(o => o.r === r)) out.push({ expr, r, id: out.length });
    }
    return out;
  }, [count, data]);

  const [rights] = useStateA(() => shuffle(pairs.map(p => p.r)));
  const [matches, setMatches] = useStateA({}); // {leftId: rightValue}
  const [selected, setSelected] = useStateA(null);
  const [mistakes, setMistakes] = useStateA(0);

  useEffectA(() => {
    if (Object.keys(matches).length === pairs.length && pairs.every(p => matches[p.id] === p.r)) {
      setTimeout(() => onFinish(pairs.length - mistakes, pairs.length), 600);
    }
  }, [matches, pairs.length, mistakes, onFinish]);

  const pickLeft = (id) => {
    if (matches[id] != null) return;
    setSelected({ side: "L", id });
    window.SFX && window.SFX.pickup();
  };
  const pickRight = (val) => {
    if (Object.values(matches).includes(val)) return;
    if (!selected || selected.side !== "L") {
      setSelected({ side: "R", val });
      return;
    }
    const left = pairs.find(p => p.id === selected.id);
    if (left.r === val) {
      setMatches({ ...matches, [selected.id]: val });
      setSelected(null);
      onCorrect();
    } else {
      setMistakes(m => m + 1);
      setSelected(null);
      onMistake();
    }
  };

  return (
    <div className="ma-match">
      <div className="ma-instruction">Toca una operación y luego su resultado.</div>
      <div className="ma-match-cols">
        <div className="ma-match-col">
          {pairs.map(p => {
            const done = matches[p.id] != null;
            const sel = selected?.side === "L" && selected.id === p.id;
            return (
              <button key={p.id} className={`ma-match-item ${done?"is-done":""} ${sel?"is-sel":""}`}
                onClick={() => pickLeft(p.id)} disabled={done}>
                {p.expr}
                {done && <span className="ma-check">✓</span>}
              </button>
            );
          })}
        </div>
        <div className="ma-match-col">
          {rights.map((r, i) => {
            const done = Object.values(matches).includes(r);
            const sel = selected?.side === "R" && selected.val === r;
            return (
              <button key={i} className={`ma-match-item ${done?"is-done":""} ${sel?"is-sel":""}`}
                onClick={() => pickRight(r)} disabled={done}>
                {r}
                {done && <span className="ma-check">✓</span>}
              </button>
            );
          })}
        </div>
      </div>
    </div>
  );
}

// =========================================================
// 3. ORDENAR — drag-arrange numbers in order
// =========================================================
function ActOrder({ theme, difficulty, onCorrect, onMistake, onFinish, data }) {
  const count = { facil: 5, media: 6, dificil: 8 }[difficulty] || 6;
  const direction = useMemoA(() => {
    if (data?.orden === 'asc' || data?.orden === 'desc') return data.orden;
    return Math.random() < 0.5 ? "asc" : "desc";
  }, [data]);

  const correct = useMemoA(() => {
    if (Array.isArray(data?.items) && data.items.length >= 3) {
      const arr = data.items.map((n) => Number(n)).filter((n) => Number.isFinite(n));
      if (arr.length >= 3) {
        arr.sort((a, b) => direction === "asc" ? a - b : b - a);
        return arr;
      }
    }

    const set = new Set();
    while (set.size < count) set.add(Math.floor(Math.random()*90)+10);
    const arr = [...set];
    arr.sort((a,b) => direction === "asc" ? a-b : b-a);
    return arr;
  }, [count, direction, data]);

  const [items, setItems] = useStateA(() => shuffle([...correct]));
  const [checked, setChecked] = useStateA(false);
  const [picking, setPicking] = useStateA(null);

  const swap = (i, j) => {
    const next = [...items];
    [next[i], next[j]] = [next[j], next[i]];
    setItems(next);
    window.SFX && window.SFX.pickup();
  };

  const onTap = (i) => {
    if (picking == null) { setPicking(i); window.SFX && window.SFX.pickup(); }
    else if (picking === i) { setPicking(null); }
    else { swap(picking, i); setPicking(null); }
  };

  const check = () => {
    setChecked(true);
    const right = items.filter((v,i)=>v===correct[i]).length;
    if (right === items.length) {
      onCorrect();
      setTimeout(() => onFinish(items.length, items.length), 500);
    } else {
      onMistake();
      setTimeout(() => setChecked(false), 1200);
    }
  };

  return (
    <div className="ma-order">
      <div className="ma-instruction">
        Ordena los números de {direction === "asc" ? "menor a mayor" : "mayor a menor"}.
      </div>
      <div className="ma-order-row">
        {items.map((n, i) => {
          const isRight = checked && n === correct[i];
          const isWrong = checked && n !== correct[i];
          return (
            <button key={i} className={`ma-order-tile ${picking===i?"is-pick":""} ${isRight?"is-right":""} ${isWrong?"is-wrong":""}`}
              onClick={() => onTap(i)}>
              {n}
            </button>
          );
        })}
      </div>
      <div className="ma-order-arrow">{direction === "asc" ? "menor →  → mayor" : "mayor →  → menor"}</div>
      <button className="ma-btn ma-btn-primary ma-btn-lg" onClick={check}>Comprobar ✓</button>
    </div>
  );
}

// =========================================================
// 4. COMPLETAR — fill the missing operand
// =========================================================
function ActFill({ theme, difficulty, onCorrect, onMistake, onFinish, data }) {
  const count = { facil: 4, media: 5, dificil: 7 }[difficulty] || 5;

  const probs = useMemoA(() => {
    if (typeof data?.texto === 'string' && Array.isArray(data?.respuestas) && data.respuestas.length) {
      return [{
        mode: 'custom',
        text: data.texto,
        ans: data.respuestas.map(r => String(r).trim()),
      }];
    }

    const out = [];
    for (let i = 0; i < count; i++) {
      const a = 2 + Math.floor(Math.random()*9);
      const b = 2 + Math.floor(Math.random()*9);
      const ops = ["+", "-", "×"];
      const op = ops[Math.floor(Math.random()*ops.length)];
      let r;
      if (op === "+") r = a + b;
      else if (op === "-") r = Math.max(a,b) - Math.min(a,b);
      else r = a * b;
      const a2 = op === "-" ? Math.max(a,b) : a;
      const b2 = op === "-" ? Math.min(a,b) : b;
      // hide one of: a, b, or r
      const hide = ["a","b","r"][Math.floor(Math.random()*3)];
      out.push({ a: a2, b: b2, op, r, hide, ans: hide==="a"?a2:hide==="b"?b2:r });
    }
    return out;
  }, [count, data]);

  const [vals, setVals] = useStateA(() => probs.map(p => p.mode === 'custom' ? p.ans.map(()=>"") : ""));
  const [checked, setChecked] = useStateA([]);

  const check = () => {
    const next = vals.map((v, i) => {
      if (probs[i].mode === 'custom') {
        const allCorrect = probs[i].ans.every((ans, j) => String(v[j]||'').trim().toLowerCase() === String(ans).toLowerCase());
        return allCorrect ? 'ok' : 'no';
      }
      return parseInt(v, 10) === probs[i].ans ? 'ok' : 'no';
    });
    setChecked(next);
    const right = next.filter(x=>x==="ok").length;
    if (right === probs.length) {
      onCorrect();
      setTimeout(() => onFinish(right, probs.length), 600);
    } else {
      const wrong = probs.length - right;
      for (let i=0;i<wrong;i++) onMistake();
      setTimeout(() => onFinish(right, probs.length), 1200);
    }
  };

  const isCustom = probs.some(p => p.mode === 'custom');
  const instruction = isCustom ? "Completa el texto con las palabras correctas." : "Escribe el número que falta en cada operación.";

  return (
    <div className="ma-fill">
      <div className="ma-instruction">{instruction}</div>
      <div className="ma-fill-list">
        {probs.map((p, i) => (
          <div key={i} className={`ma-fill-row ${checked[i]||""}`}>
            <span className="ma-fill-num">{i+1}.</span>
            {p.mode === 'custom' ? (() => {
              const parts = p.text.split(/_+/);
              return (
                <span className="ma-eq" style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                  {parts.map((part, partIdx) => (
                    <React.Fragment key={partIdx}>
                      <span>{part}</span>
                      {partIdx < parts.length - 1 && partIdx < p.ans.length && (
                        <FillBox type="text" value={vals[i][partIdx]} onChange={v => {
                          const n = [...vals];
                          const arr = [...n[i]];
                          arr[partIdx] = v;
                          n[i] = arr;
                          setVals(n);
                        }} state={checked[i]} />
                      )}
                    </React.Fragment>
                  ))}
                </span>
              );
            })() : (
              <span className="ma-eq">
                {p.hide === "a" ? <FillBox value={vals[i]} onChange={v=>{const n=[...vals];n[i]=v;setVals(n);}} state={checked[i]}/> : <span>{p.a}</span>}
                <span className="ma-op">{p.op}</span>
                {p.hide === "b" ? <FillBox value={vals[i]} onChange={v=>{const n=[...vals];n[i]=v;setVals(n);}} state={checked[i]}/> : <span>{p.b}</span>}
                <span className="ma-op">=</span>
                {p.hide === "r" ? <FillBox value={vals[i]} onChange={v=>{const n=[...vals];n[i]=v;setVals(n);}} state={checked[i]}/> : <span>{p.r}</span>}
              </span>
            )}
          </div>
        ))}
      </div>
      <button className="ma-btn ma-btn-primary ma-btn-lg" onClick={check}>Comprobar ✓</button>
    </div>
  );
}
function FillBox({ value, onChange, state, type = "number" }) {
  return (
    <input className={`ma-fillbox ${state||""}`} type={type} value={value}
      onChange={e=>onChange(e.target.value)} />
  );
}

// =========================================================
// 8. RESPUESTA ESCRITA — answer math problems
// =========================================================
function ActAnswer({ theme, difficulty, onCorrect, onMistake, onFinish, attemptsLeft, data }) {
  const count = { facil: 5, media: 7, dificil: 10 }[difficulty] || 7;
  
  const isCustom = typeof data?.pregunta === 'string' || (Array.isArray(data?.preguntas) && data.preguntas.length > 0);

  const probs = useMemoA(() => {
    if (Array.isArray(data?.preguntas) && data.preguntas.length > 0) {
      return data.preguntas.map(p => ({
        expr: String(p.pregunta || p.q || ''),
        r: String(p.respuesta || p.respuesta_correcta || p.a || ''),
      })).filter(p => p.expr && p.r);
    }
    if (typeof data?.pregunta === 'string' && data?.respuesta_correcta != null) {
      return [{ expr: data.pregunta, r: String(data.respuesta_correcta) }];
    }

    const out = [];
    for (let i = 0; i < count; i++) {
      const a = 5 + Math.floor(Math.random()*15);
      const b = 2 + Math.floor(Math.random()*10);
      const op = ["+", "-", "×", "÷"][Math.floor(Math.random()*4)];
      let r, expr;
      if (op === "+") { r = a + b; expr = `${a} + ${b}`; }
      else if (op === "-") { r = a - b; expr = `${a} - ${b}`; }
      else if (op === "×") { r = a * b; expr = `${a} × ${b}`; }
      else { r = a; expr = `${a*b} ÷ ${b}`; }
      out.push({ expr, r });
    }
    return out;
  }, [count, data]);

  const [idx, setIdx] = useStateA(0);
  const [val, setVal] = useStateA("");
  const [right, setRight] = useStateA(0);
  const [feedback, setFeedback] = useStateA(null);
  const inputRef = useRefA();

  useEffectA(() => { inputRef.current?.focus(); }, [idx]);

  const submit = (e) => {
    e?.preventDefault();
    if (val === "") return;
    const expected = probs[idx].r;
    const ok = String(val).trim().toLowerCase() === String(expected).trim().toLowerCase();
    setFeedback(ok ? "ok" : "no");
    if (ok) { onCorrect(); setRight(r => r + 1); }
    else onMistake();
    setTimeout(() => {
      setFeedback(null);
      setVal("");
      if (idx + 1 < probs.length) setIdx(i => i + 1);
      else onFinish(right + (ok?1:0), probs.length);
    }, 700);
  };

  const p = probs[idx];
  const instruction = isCustom ? "Lee la pregunta y escribe tu respuesta." : "Resuelve cada operación y escribe el resultado.";

  return (
    <div className="ma-answer">
      <div className="ma-instruction">{instruction}</div>
      <div className="ma-answer-progress">
        Pregunta {idx+1} de {probs.length} · <strong>{right}</strong> aciertos
      </div>
      <form className={`ma-answer-card ${feedback||""}`} onSubmit={submit}>
        <div className="ma-answer-expr" style={{ fontSize: isCustom ? '1.5rem' : undefined, whiteSpace: 'pre-wrap' }}>
          {p.expr}{isCustom ? "" : " ="}
        </div>
        <input ref={inputRef} className="ma-answer-input" type={isCustom ? "text" : "number"} value={val}
          onChange={e=>setVal(e.target.value)} placeholder="Escribe aquí..."/>
        <button className="ma-btn ma-btn-primary ma-btn-lg" type="submit" disabled={val===""}>
          Responder ↵
        </button>
      </form>
      {!isCustom && (
        <Numpad onPress={(d) => {
          if (d === "←") setVal(v => String(v).slice(0,-1));
          else if (d === "OK") submit();
          else setVal(v => (String(v) + d).slice(0,4));
        }}/>
      )}
    </div>
  );
}
function Numpad({ onPress }) {
  const keys = ["1","2","3","4","5","6","7","8","9","←","0","OK"];
  return (
    <div className="ma-numpad">
      {keys.map(k => (
        <button key={k} className={`ma-numkey ${k==="OK"?"ma-numkey-ok":""}`} onClick={()=>{onPress(k); window.SFX && window.SFX.click();}}>{k}</button>
      ))}
    </div>
  );
}

Object.assign(window, { ActMemory, ActMatch, ActOrder, ActFill, ActAnswer, shuffle, pickN, range });
