"use strict";

const STORAGE_KEY = "celest-v1-shuffle-bags";
const themeDisplay = document.getElementById("theme");
const revelation = document.getElementById("revelation");
const metadata = document.getElementById("metadata");
const diceButton = document.getElementById("dice");
const notice = document.getElementById("notice");

let dataset = null;
let currentTheme = null;
let currentResponse = null;
let currentAnswer = "";
let bags = loadBags();

function loadBags() {
  try {
    return JSON.parse(localStorage.getItem(STORAGE_KEY)) || {};
  } catch {
    return {};
  }
}

function saveBags() {
  try {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(bags));
  } catch {
    // プライベートモード等では保存せず、その回だけ抽選を続ける。
  }
}

function randomInt(max) {
  if (max <= 0) return 0;
  const values = new Uint32Array(1);
  const limit = Math.floor(0x100000000 / max) * max;
  do {
    crypto.getRandomValues(values);
  } while (values[0] >= limit);
  return values[0] % max;
}

function shuffledIndices(count) {
  const values = Array.from({length: count}, (_, index) => index);
  for (let index = count - 1; index > 0; index -= 1) {
    const selected = randomInt(index + 1);
    [values[index], values[selected]] = [values[selected], values[index]];
  }
  return values;
}

function ensureJapanesePeriod(text) {
  const answer = String(text || "").trim();
  return !answer || answer.endsWith("。") ? answer : `${answer}。`;
}

function normalizeBag(theme) {
  const key = theme.theme;
  const count = theme.responses.length;
  const existing = bags[key];
  const invalid = !existing
    || !Array.isArray(existing.remaining)
    || typeof existing.shown !== "number"
    || existing.remaining.some(
      (index) => !Number.isInteger(index) || index < 0 || index >= count
    );

  if (invalid || existing.remaining.length === 0) {
    bags[key] = {remaining: shuffledIndices(count), shown: 0};
  }
  return bags[key];
}

function drawResponse(theme) {
  const bag = normalizeBag(theme);
  const index = bag.remaining.pop();
  bag.shown += 1;
  saveBags();

  currentTheme = theme;
  currentResponse = theme.responses[index];
  currentAnswer = ensureJapanesePeriod(currentResponse.answer);
  themeDisplay.value = theme.theme;
  revelation.value = currentAnswer;
  metadata.textContent =
    `${currentResponse.respondent_id}  •  ${bag.shown} / ${theme.responses.length}`;
}

function rollDice() {
  if (!dataset?.themes?.length) return;
  diceButton.classList.remove("rolling");
  void diceButton.offsetWidth;
  diceButton.classList.add("rolling");
  drawResponse(dataset.themes[randomInt(dataset.themes.length)]);
}

function flash(message) {
  notice.textContent = message;
  notice.hidden = false;
  window.setTimeout(() => { notice.hidden = true; }, 1300);
}

function initialize() {
  dataset = window.CELEST_DATA;

  const actualResponseCount =
    dataset?.themes?.reduce(
      (total, theme) => {
        return total + (
          theme.responses?.length || 0
        );
      },
      0
    );

  const hasEmptyTheme =
    dataset?.themes?.some(
      (theme) => !theme.responses?.length
    );

  if (
    !dataset
    || !Array.isArray(dataset.themes)
    || dataset.themes.length !== 24
    || actualResponseCount !== 1000
    || hasEmptyTheme
  ) {
    themeDisplay.value =
      "回答データを読み込めません";

    revelation.value =
      "販売元へお問い合わせください。";

    return;
  }

  themeDisplay.value = "Tap Dice";
  diceButton.disabled = false;
}

diceButton.addEventListener("click", rollDice);

document.getElementById("clear").addEventListener("click", () => {
  themeDisplay.value = "Tap Dice";
  revelation.value = "";
  metadata.textContent = "";
  currentTheme = null;
  currentResponse = null;
  currentAnswer = "";
  diceButton.focus();
});

document.getElementById("copy").addEventListener("click", async () => {
  if (!revelation.value) return;
  try {
    await navigator.clipboard.writeText(revelation.value);
  } catch {
    revelation.focus();
    revelation.select();
    document.execCommand("copy");
    window.getSelection()?.removeAllRanges();
  }
  flash("COPIED");
});

document.getElementById("save").addEventListener("click", () => {
  if (!currentTheme || !currentResponse) return;
  const text = [
    "- Sample Celest V1 -",
    "1K People's Voice here.",
    "",
    "THEME:",
    currentTheme.theme,
    "",
    "REVELATION:",
    currentAnswer,
    "",
    `VOICE: No. ${currentResponse.respondent_id}`,
  ].join("\r\n");
  const blob = new Blob(["\ufeff", text], {
    type: "text/plain;charset=utf-8",
  });
  const link = document.createElement("a");
  link.href = URL.createObjectURL(blob);
  link.download = `celest_${currentResponse.respondent_id}.txt`;
  link.click();
  URL.revokeObjectURL(link.href);
});

initialize();
