import { openGameSelectorModal, closeGameSelectorModal } from "../components/game-selector-modal.js";
import { showToast } from "../components/toast.js";
import { escapeHtml } from "../utils/escape-html.js";
import { t } from "../config/site.js";
import {
  DEFAULT_SLOT_PROVIDER,
  loadSlotGamesRoulette,
} from "../utils/slot-games-cache.js";

const CARD_W = 168;
const CARD_GAP = 12;
const CARD_STEP = CARD_W + CARD_GAP;
const SPIN_DURATION_MS = 5200;
const SPIN_EASING = "cubic-bezier(0.12, 0.72, 0.18, 1)";
/** Şeritte kaç kez aynı oyun listesi tekrarlanır (sonsuz döngü hissi; düşük = daha hızlı ilk render) */
const REPEAT_BLOCKS = 9;

let games = [];
let providers = [];
let currentProvider = DEFAULT_SLOT_PROVIDER;
let recentWinnerKeys = [];
let spinning = false;
let currentOffset = 0;
let reelTrack = null;
let reelViewport = null;
let spinBtn = null;
let stateEl = null;
let resizeObserver = null;

function prefersReducedMotion() {
  return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
}

function centerPadding() {
  if (!reelViewport) return 0;
  const vw = reelViewport.clientWidth || 320;
  return Math.max(0, vw / 2 - CARD_W / 2);
}

function offsetForGlobalIndex(globalIndex) {
  return globalIndex * CARD_STEP - centerPadding();
}

/** İmleç altındaki kartın games[] içindeki indeksi */
function localIndexFromOffset(offsetPx) {
  if (!games.length) return 0;
  const global = globalIndexFromOffset(offsetPx);
  const mid = middleBlockStartIndex();
  return ((global - mid) % games.length + games.length) % games.length;
}

/** Görünümü koruyarak şeridi orta bloğa taşır (sonraki çeviriler için alan) */
function normalizeStripToMiddle(localIndex) {
  alignToGameIndex(localIndex, false);
}

function providerDisplayName(id) {
  const key = String(id || currentProvider || "").toLowerCase();
  const found = providers.find((p) => String(p.id).toLowerCase() === key);
  if (found?.label) return found.label;
  return key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[-_]/g, " ");
}

function showWinnerResult(localIndex) {
  const idx = ((localIndex % games.length) + games.length) % games.length;
  const game = games[idx];
  if (!game) return;

  reelTrack?.querySelectorAll(".game-selector__card").forEach((c) => c.classList.remove("game-selector__card--winner"));
  const mid = middleBlockStartIndex();
  const cards = reelTrack?.querySelectorAll(".game-selector__card");
  const global = mid + idx;
  if (cards?.[global]) cards[global].classList.add("game-selector__card--winner");

  openGameSelectorModal(
    { name: game.name, image: game.image, rtp: game.rtp },
    {
      providerLabel: providerDisplayName(currentProvider),
      onSpinAgain: () => onSpin(),
    }
  );
}

function applyWinnerUi(localIndex) {
  showWinnerResult(localIndex);
}

function buildStripHtml(list) {
  if (!list.length) return "";
  const blocks = [];
  for (let b = 0; b < REPEAT_BLOCKS; b++) {
    for (const g of list) {
      const img = g.image
        ? `<img class="game-selector__card-img" src="${escapeHtml(g.image)}" alt="" loading="lazy" decoding="async" />`
        : `<div class="game-selector__card-img game-selector__card-img--placeholder" aria-hidden="true">🎰</div>`;
      blocks.push(`
        <article class="game-selector__card" data-game-id="${escapeHtml(g.id)}">
          ${img}
          <span class="game-selector__card-title">${escapeHtml(g.name)}</span>
        </article>
      `);
    }
  }
  return blocks.join("");
}

function middleBlockStartIndex() {
  return games.length * Math.floor(REPEAT_BLOCKS / 2);
}

function stripCardCount() {
  return games.length * REPEAT_BLOCKS;
}

function globalIndexFromOffset(offsetPx) {
  return Math.round((offsetPx + centerPadding()) / CARD_STEP);
}

/** Aynı oyunu gösterirken global indeksi şerit sınırlarına çeker */
function clampEndGlobal(endGlobal) {
  const n = games.length;
  if (n <= 0) return endGlobal;
  const maxEnd = stripCardCount() - n - 1;
  let end = endGlobal;
  while (end > maxEnd) end -= n;
  return end;
}

function maxSpinLaps() {
  const n = games.length;
  if (n <= 0) return 0;
  const mid = middleBlockStartIndex();
  const maxEnd = stripCardCount() - n - 1;
  return Math.max(2, Math.floor((maxEnd - mid - (n - 1)) / n));
}

function setTrackOffset(px, animate = false) {
  if (!reelTrack) return;
  currentOffset = px;
  reelTrack.style.transition = animate ? `transform ${SPIN_DURATION_MS}ms ${SPIN_EASING}` : "none";
  reelTrack.style.transform = `translate3d(${-px}px, 0, 0)`;
}

function alignToGameIndex(localIndex, animate = false) {
  const global = middleBlockStartIndex() + ((localIndex % games.length) + games.length) % games.length;
  setTrackOffset(offsetForGlobalIndex(global), animate);
}

function secureRandomInt(max) {
  if (max <= 0) return 0;
  if (typeof crypto !== "undefined" && crypto.getRandomValues) {
    const buf = new Uint32Array(1);
    crypto.getRandomValues(buf);
    return buf[0] % max;
  }
  return Math.floor(Math.random() * max);
}

function shuffleInPlace(arr) {
  for (let i = arr.length - 1; i > 0; i--) {
    const j = secureRandomInt(i + 1);
    [arr[i], arr[j]] = [arr[j], arr[i]];
  }
  return arr;
}

function gameKey(g) {
  return String(g?.id || g?.name || "")
    .trim()
    .toLowerCase();
}

function dedupeGames(list) {
  const seen = new Set();
  const out = [];
  for (const g of list) {
    if (!g || typeof g !== "object") continue;
    const key = gameKey(g);
    if (!key || seen.has(key)) continue;
    seen.add(key);
    out.push(g);
  }
  return out;
}

function prepareGamesList(list) {
  return shuffleInPlace(dedupeGames(list));
}

function rebuildStrip() {
  if (!reelTrack || !games.length) return;
  reelTrack.innerHTML = buildStripHtml(games);
}

function pickWinnerIndex() {
  const n = games.length;
  if (n <= 0) return 0;
  if (n === 1) return 0;

  const avoid = new Set(recentWinnerKeys);
  let pool = games.map((g, i) => ({ i, key: gameKey(g) }));
  if (avoid.size > 0 && avoid.size < n) {
    const filtered = pool.filter((p) => !avoid.has(p.key));
    if (filtered.length) pool = filtered;
  }

  const pick = pool[secureRandomInt(pool.length)];
  recentWinnerKeys.push(pick.key);
  if (recentWinnerKeys.length > Math.min(5, Math.max(2, n - 1))) {
    recentWinnerKeys.shift();
  }
  return pick.i;
}

function applyProviderList(list) {
  if (!Array.isArray(list) || !list.length) return false;
  providers = list;
  const ids = providers.map((p) => String(p.id || "").toLowerCase());
  if (!ids.includes(String(currentProvider || "").toLowerCase())) {
    currentProvider = providers[0].id;
  }
  return true;
}

function initProviders() {
  return applyProviderList([{ id: DEFAULT_SLOT_PROVIDER, label: "Pragmatic Play" }]);
}

function applyGamesPayload(data) {
  if (Array.isArray(data.providers) && data.providers.length) {
    applyProviderList(data.providers);
  }
  if (data.provider && typeof data.provider === "string") {
    currentProvider = data.provider;
  }
  return Array.isArray(data.games) ? data.games : [];
}

function setUiLoading(msg) {
  if (stateEl) {
    stateEl.textContent = msg || "";
    stateEl.classList.toggle("game-selector__state--error", false);
  }
  if (spinBtn) spinBtn.disabled = true;
}

function setUiError(msg) {
  if (stateEl) {
    stateEl.textContent = msg || t("gameSelectorError");
    stateEl.classList.add("game-selector__state--error");
  }
  if (spinBtn) spinBtn.disabled = true;
}

function setUiReady() {
  if (stateEl) {
    stateEl.textContent = "";
    stateEl.classList.remove("game-selector__state--error");
  }
  if (spinBtn) spinBtn.disabled = !games.length || spinning;
}

function mountGamesList(list) {
  games = prepareGamesList(list);
  recentWinnerKeys = [];
  if (!games.length) {
    setUiError(t("gameSelectorEmpty"));
    return false;
  }
  rebuildStrip();
  const startAt = secureRandomInt(games.length);
  alignToGameIndex(startAt, false);
  setUiReady();
  return true;
}

async function loadProvider(provider) {
  currentProvider = provider;
  setUiLoading(t("gameSelectorLoading"));
  if (reelTrack) reelTrack.innerHTML = "";
  closeGameSelectorModal();

  try {
    const data = await loadSlotGamesRoulette(provider);
    mountGamesList(applyGamesPayload(data));
  } catch {
    setUiError(t("gameSelectorError"));
    showToast(t("gameSelectorError"), "error");
  }
}

function onSpin() {
  if (spinning || !games.length || !reelTrack) return;
  spinning = true;
  if (spinBtn) spinBtn.disabled = true;
  closeGameSelectorModal();
  reelTrack?.querySelectorAll(".game-selector__card").forEach((c) => c.classList.remove("game-selector__card--winner"));

  const n = games.length;
  const prevLocal = localIndexFromOffset(currentOffset);
  const prevKey = gameKey(games[prevLocal]);

  shuffleInPlace(games);
  rebuildStrip();
  let startLocal = games.findIndex((g) => gameKey(g) === prevKey);
  if (startLocal < 0) startLocal = secureRandomInt(n);
  alignToGameIndex(startLocal, false);

  const winner = pickWinnerIndex();
  const startGlobal = globalIndexFromOffset(currentOffset);
  const forward = (winner - startLocal + n) % n;
  let fullLaps = prefersReducedMotion() ? 0 : 3 + secureRandomInt(3);
  fullLaps = Math.min(fullLaps, maxSpinLaps());
  let endGlobal = startGlobal + fullLaps * n + forward;
  endGlobal = clampEndGlobal(endGlobal);
  const endOffset = offsetForGlobalIndex(endGlobal);

  requestAnimationFrame(() => {
    setTrackOffset(endOffset, !prefersReducedMotion());
  });

  let finished = false;
  const finishSpin = () => {
    if (finished) return;
    finished = true;
    spinning = false;
    const landed = localIndexFromOffset(endOffset);
    normalizeStripToMiddle(landed);
    applyWinnerUi(landed);
    if (spinBtn) spinBtn.disabled = false;
  };

  if (prefersReducedMotion()) {
    finishSpin();
    return;
  }

  const onEnd = (e) => {
    if (e.target !== reelTrack || e.propertyName !== "transform") return;
    reelTrack.removeEventListener("transitionend", onEnd);
    finishSpin();
  };
  reelTrack.addEventListener("transitionend", onEnd);
  setTimeout(finishSpin, SPIN_DURATION_MS + 150);
}

function bindControls(root) {
  spinBtn = root.querySelector("#game-selector-spin");
  reelTrack = root.querySelector("#game-selector-track");
  reelViewport = root.querySelector("#game-selector-viewport");
  stateEl = root.querySelector("#game-selector-state");

  if (reelTrack) {
    reelTrack.style.setProperty("--gs-card-w", `${CARD_W}px`);
    reelTrack.style.setProperty("--gs-gap", `${CARD_GAP}px`);
  }

  spinBtn?.addEventListener("click", onSpin);

  if (reelViewport && typeof ResizeObserver !== "undefined") {
    resizeObserver?.disconnect();
    resizeObserver = new ResizeObserver(() => {
      if (!spinning && games.length) {
        normalizeStripToMiddle(localIndexFromOffset(currentOffset));
      }
    });
    resizeObserver.observe(reelViewport);
  }
}

export async function renderGameSelectorPage(el) {
  el.innerHTML = `
    <section class="game-selector-page relative w-full min-w-0 space-y-8 px-1 pb-4">
      <header class="relative overflow-hidden rounded-3xl border border-white/[0.08] bg-[#1e2739] p-8 shadow-panel ring-1 ring-white/[0.04] sm:p-10">
        <div class="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_80%_60%_at_100%_0%,rgba(22,119,255,0.09),transparent)]"></div>
        <div class="relative space-y-3">
          <span class="inline-flex items-center gap-2 rounded-full border border-accent/25 bg-accent/10 px-3 py-1 text-[11px] font-semibold uppercase tracking-[0.18em] text-accent-bright">${t("gameSelectorEyebrow")}</span>
          <h1 class="text-3xl font-bold tracking-tight text-white sm:text-4xl">${t("gameSelectorTitle")}</h1>
          <p class="max-w-2xl text-sm leading-relaxed text-slate-400 sm:text-base">${t("gameSelectorSubtitle")}</p>
        </div>
      </header>
      <div class="game-selector-panel w-full">
        <div class="game-selector__reel-wrap">
          <div class="game-selector__pointer" aria-hidden="true"></div>
          <div class="game-selector__pointer-line" aria-hidden="true"></div>
          <div id="game-selector-viewport" class="game-selector__reel-viewport">
            <div id="game-selector-track" class="game-selector__reel-track"></div>
          </div>
        </div>
        <button type="button" id="game-selector-spin" class="game-selector__spin k-btn k-btn--primary btn-site-primary btn-site-action w-full justify-center gap-2 rounded-xl py-3.5 text-sm font-bold uppercase tracking-wide shadow-glow-sm sm:text-base" disabled>
          <svg class="h-5 w-5 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
          ${t("gameSelectorSpin")}
        </button>
        <p id="game-selector-state" class="game-selector__state" role="status"></p>
      </div>
    </section>
  `;

  bindControls(el);
  if (!initProviders()) {
    setUiError(t("gameSelectorProvidersError"));
    showToast(t("gameSelectorProvidersError"), "error");
    return () => {
      resizeObserver?.disconnect();
      resizeObserver = null;
      spinning = false;
    };
  }
  await loadProvider(currentProvider);

  return () => {
    resizeObserver?.disconnect();
    resizeObserver = null;
    spinning = false;
  };
}
