Source: scripts/shop.js

import { update_points, fetch_user_info, add_or_update_card, load_cards_from_local } from "../index.js";
import { CARD_NAMES, RARITIES, BIOS, COURSES, GUARANTEE_THRESHOLDS } from "./card-values.js";

export {
  get_random_element,
  update_pity_counters,
  get_random_rarity,
  generate_random_card,
  load_pity_counters,
  save_pity_counters,
  get_rarity_display_color,
  update_cost,
  update_container_rarity,
  display_placeholder,
  init,
  create_light_rays,
  show_congrats_animation,
  update_tooltip,
  update_guarantee_display,
  update_points_display,

};

// TODO: Consider moving constants to config file
let cover_opened = false;
let COST = 100;

window.addEventListener("DOMContentLoaded", init);

/**
 * @description Returns a random element from an array.
 * @param {Array} arr The array to choose from.
 * @returns {*} A randomly selected element from the array.
 */
function get_random_element(arr) {
  return arr[Math.floor(Math.random() * arr.length)];
}

/**
 * @description Updates pity counters based on obtained rarity.
 * @param {string} obtained_rarity The rarity that was obtained.
 * @returns {Object} Updated counters.
 */
function update_pity_counters(obtained_rarity) {
  const counters = load_pity_counters();
  const rarity_hierarchy = ["common", "uncommon", "rare", "epic", "legendary", "special-edition"];
  const obtained_index = rarity_hierarchy.indexOf(obtained_rarity);

  // Increment counters for rarities above what we got
  for (let i = obtained_index + 1; i < rarity_hierarchy.length; i++) {
    const rarity = rarity_hierarchy[i];
    if (counters[rarity] !== undefined) {
      counters[rarity]++;
    }
  }

  // Reset counters at or below what we got
  for (let i = 0; i <= obtained_index; i++) {
    const rarity = rarity_hierarchy[i];
    if (counters[rarity] !== undefined) {
      counters[rarity] = 0;
    }
  }

  save_pity_counters(counters);
  return counters;
}

/**
 * @description Randomly selects a rarity, checking guarantees first.
 * @param {Array} rarities Array of rarity objects.
 * @returns {string} Selected rarity type.
 */
function get_random_rarity(rarities) {
  const counters = load_pity_counters();

  // Check guarantees from highest to lowest
  if (counters["special-edition"] >= GUARANTEE_THRESHOLDS["special-edition"]) {
    return "special-edition";
  }
  if (counters.legendary >= GUARANTEE_THRESHOLDS.legendary) {
    return "legendary";
  }
  if (counters.epic >= GUARANTEE_THRESHOLDS.epic) {
    return "epic";
  }
  if (counters.rare >= GUARANTEE_THRESHOLDS.rare) {
    return "rare";
  }

  // Normal RNG
  const rand = Math.random() * 100;
  let sum = 0;
  for (let rarity of rarities) {
    sum += rarity.chance;
    if (rand <= sum) {
      return rarity.type;
    }
  }
  return rarities[0].type; // fallback
}

/**
 * @description Generates a random card object with a name, rarity, and metadata.
 * @returns {Object} A card object.
 */
function generate_random_card() {
  const name = get_random_element(CARD_NAMES);
  const rarity = get_random_rarity(RARITIES);
  return {
    name,
    rarity,
    quantity: 1,
    bio: BIOS[name] || "A mysterious card.",
    course: COURSES[name] || "???"
  };
}

/**
 * @description Loads pity counters from local storage.
 * @returns {Object} Pity counters object.
 */
function load_pity_counters() {
  const data = localStorage.getItem("pity_counters");
  return data ? JSON.parse(data) : {
    rare: 0,
    epic: 0,
    legendary: 0,
    "special-edition": 0
  };
}

/**
 * @description Saves pity counters to local storage.
 * @param {Object} counters Counters to save.
 * @returns {void}
 */
function save_pity_counters(counters) {
  localStorage.setItem("pity_counters", JSON.stringify(counters));
}

/**
 * @description Creates light ray effects for card reveal.
 * @param {string} rarity The rarity of the card.
 * @returns {void}
 */
function create_light_rays(rarity) {
  const container = document.getElementById("card-container");

  // Remove any existing light rays
  const existing_rays = container.querySelector(".light-rays");
  if (existing_rays) {
    existing_rays.remove();
  }

  const light_rays_div = document.createElement("div");
  light_rays_div.className = "light-rays";

  const colors = {
    common: "#FFFFFF",
    uncommon: "#22C55E",
    rare: "#3B82F6",
    epic: "#A855F7",
    legendary: "#FFD700",
    "special-edition": "linear-gradient(45deg, #FF006E, #FFD700)"
  };

  // Create multiple light rays
  for (let i = 0; i < 12; i++) {
    const ray = document.createElement("div");
    ray.className = "light-ray";
    ray.style.setProperty("--rotation", `${i * 30}deg`);
    ray.style.background = colors[rarity] || colors.common;
    ray.style.animationDelay = `${i * 0.05}s`;
    light_rays_div.appendChild(ray);
  }

  container.appendChild(light_rays_div);

  // Remove after animation
  setTimeout(() => light_rays_div.remove(), 2000);
}

/**
 * @description Shows congratulations animation with particles.
 * @param {string} rarity The rarity of the card.
 * @returns {void}
 */
function show_congrats_animation(rarity) {
  const container = document.getElementById("gen-container");

  // Remove any existing congratulations animation
  const existing_congrats = container.querySelector(".congrats-animation");
  if (existing_congrats) {
    existing_congrats.remove();
  }

  const congrats_div = document.createElement("div");
  congrats_div.className = "congrats-animation";

  const rarity_text = {
    common: "COMMON",
    uncommon: "UNCOMMON!",
    rare: "RARE!",
    epic: "✨ EPIC! ✨",
    legendary: "⚡ LEGENDARY! ⚡",
    "special-edition": "🌟 SPECIAL EDITION! 🌟"
  };

  const congrats_text = document.createElement("div");
  congrats_text.className = `congrats-text congrats-${rarity}`;
  congrats_text.textContent = rarity_text[rarity];
  congrats_div.appendChild(congrats_text);

  // Create particle effects for rare and above
  if (['rare', 'epic', 'legendary', 'special-edition'].includes(rarity)) {
    const particles_div = document.createElement("div");
    particles_div.className = "congrats-particles";

    const particle_colors = {
      rare: ['#3B82F6', '#60A5FA', '#2563EB'],
      epic: ['#A855F7', '#C084FC', '#9333EA'],
      legendary: ['#FFD700', '#FFC700', '#FFE700'],
      "special-edition": ['#FF006E', '#FFD700', '#00D9FF', '#FF00FF']
    };

    const colors = particle_colors[rarity] || ['#FFD700'];
    const particle_count = rarity === 'special-edition' ? 30 : rarity === 'legendary' ? 20 : 15;

    for (let i = 0; i < particle_count; i++) {
      const particle = document.createElement("div");
      particle.className = "particle";
      particle.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
      particle.style.left = "50%";
      particle.style.top = "50%";

      const angle = (Math.PI * 2 * i) / particle_count;
      const distance = 50 + Math.random() * 50;
      const x = Math.cos(angle) * distance;
      const y = Math.sin(angle) * distance;

      particle.style.setProperty('--x', `${x}px`);
      particle.style.setProperty('--y', `${y}px`);
      particle.style.animationDelay = `${Math.random() * 0.3}s`;

      if (rarity === 'special-edition') {
        particle.style.boxShadow = `0 0 10px ${particle.style.backgroundColor}`;
      }

      particles_div.appendChild(particle);
    }

    congrats_div.appendChild(particles_div);
  }

  container.appendChild(congrats_div);

  // Remove after animation
  setTimeout(() => congrats_div.remove(), 2000);
}

/**
 * @description Updates the container background based on rarity.
 * @param {string} rarity The rarity to apply.
 * @returns {void}
 */
function update_container_rarity(rarity) {
  const container = document.getElementById("gen-container");
  // Remove all previous rarity classes
  container.classList.remove('rarity-common', 'rarity-uncommon', 'rarity-rare',
    'rarity-epic', 'rarity-legendary', 'rarity-special-edition');
  // Add new rarity class
  if (rarity) {
    container.classList.add(`rarity-${rarity}`);
  }
}

/**
 * @description Displays a placeholder card.
 * @param {boolean} is_first_purchase If this is user's first purchase.
 * @returns {void}
 */
function display_placeholder(is_first_purchase = true) {
  const container = document.getElementById("card-container");
  const placeholder_text = is_first_purchase
    ? "Click below to purchase your first pack!"
    : "Click below to purchase a pack!";

  container.innerHTML = `
    <div class="placeholder-card">
      <div class="pack-wrapper">
        <img src="./assets/misc-images/pack_left.webp" alt="placeholder pack left" class="pack-left">
        <img src="./assets/misc-images/pack_right.webp" alt="placeholder pack right" class="pack-right">
      </div>
      <div class="placeholder-text">${placeholder_text}</div>
    </div>
  `;
}

/**
 * @description Displays a card and overlays a pack-cover.
 * @param {Object} card The card object to display.
 * @returns {void}
 */
function display_card(card) {
  const container = document.getElementById("card-container");
  container.innerHTML = ""; // Clear previous content

  const frog_card = document.createElement("frog-card");
  frog_card.data = card;

  const cover = document.createElement("pack-cover");
  cover.classList.add("with-glow", `rarity-${card.rarity}`);

  container.appendChild(frog_card);
  container.appendChild(cover);

  // Create light rays immediately for unopened pack
  setTimeout(() => create_light_rays(card.rarity), 100);

  cover_opened = false;
}

/**
 * @description Updates the points display on the page using user data.
 * @returns {void}
 */
function update_points_display() {
  const data = fetch_user_info();
  const points = data?.points ?? 0;
  const display = document.getElementById("points-display");
  if (display) {
    display.textContent = `${points}`;
  }

  // Update button visual state based on points
  const generate_btn = document.getElementById("generate-card");
  if (generate_btn) {
    if (points < COST) {
      generate_btn.classList.add("no-points");
    } else {
      generate_btn.classList.remove("no-points");
    }
  }
}

/**
 * @description Updates the card generation cost displayed on the page.
 * @returns {void}
 */
function update_cost() {
  const cost_display = document.getElementById("cost");
  if (cost_display) {
    cost_display.innerHTML = `
  Cost: 
  <span class="cost-amount">
    ${COST}<img id="cost-img" src="/assets/misc-images/point.webp" alt="coin" class="coin-icon">
  </span>
`;
  }
}

/**
 * @description Updates tooltip with drop rates and guarantees.
 * @returns {void}
 */
function update_tooltip() {
  const tooltip_text = document.querySelector(".tooltip-text");
  if (tooltip_text) {
    tooltip_text.innerHTML = `
      Drop Rates:<br>
      <span class="rarity-common">Common: 55%</span><br>
      <span class="rarity-uncommon">Uncommon: 25%</span><br>
      <span class="rarity-rare">Rare: 15% (G:10)</span><br>
      <span class="rarity-epic">Epic: 4% (G:20)</span><br>
      <span class="rarity-legendary">Legendary: 0.9% (G:50)</span><br>
      <span class="rarity-special-edition">Special-Edition: 0.1% (G:100)</span><br>
      <span style="font-size: 0.85rem; color: #ccc; margin-top: 0.5rem; display: block; border-top: 1px solid #555; padding-top: 0.5rem;">G = Guaranteed after X buys</span>
    `;
  }
}

/**
 * @description Updates the guarantee progress bar.
 * @returns {void}
 */
function update_guarantee_display() {
  const counters = load_pity_counters();
  const guarantee_display = document.getElementById("guarantee-display");

  if (!guarantee_display) {
    return;
  }

  // Show Special Edition progress
  const special_count = counters["special-edition"];
  const special_threshold = GUARANTEE_THRESHOLDS["special-edition"];
  const percentage = (special_count / special_threshold) * 100;

  guarantee_display.innerHTML = `
    <div class="guarantee-text">${special_count}/${special_threshold} to guaranteed Special Edition</div>
    <div class="guarantee-bar">
      <div class="guarantee-fill guarantee-special-edition" style="width: ${percentage}%"></div>
    </div>
  `;
}

/**
 * @description Gets the display color for a rarity (brighter for dark background).
 * @param {string} rarity The rarity type.
 * @returns {string} The color code.
 */
function get_rarity_display_color(rarity) {
  const colors = {
    common: "#FFFFFF",
    uncommon: "#4ADE80",
    rare: "#60A5FA",
    epic: "#C084FC",
    legendary: "#FFD700",
    "special-edition": "#FFD700"  // Use gold instead of gradient for simplicity
  };
  return colors[rarity] || colors.common;
}

/**
 * @description Initializes the shop page.
 */
function init() {
  const generate_btn = document.getElementById("generate-card");
  const result_display = document.getElementById("result");

  update_points_display();
  update_cost();
  update_tooltip();
  update_guarantee_display();

  // Check if user has any cards to determine placeholder text
  const existing_cards = load_cards_from_local();
  const is_first_purchase = existing_cards.length === 0;

  // Always display placeholder when entering shop
  display_placeholder(is_first_purchase);

  // Clear any previous container styling and result text
  update_container_rarity(null);
  result_display.innerHTML = "";
  result_display.style.visibility = "visible";
  result_display.style.position = "relative";
  result_display.style.zIndex = "1";

  // Store handler reference to prevent double-firing
  let current_open_handler = null;

  generate_btn.addEventListener("click", function () {
    const user = fetch_user_info();
    if (!user || user.points < COST) {
      result_display.innerHTML = `
    <div style="font-weight: bold; color: red;">❌ NOT ENOUGH POINTS. ❌</div>
    <div style="margin-top: 0.3rem;">
      <a href="/clicker.html" style="color: #FFD700; font-weight: bold; text-decoration: none;">
        CLICK HERE TO EARN MORE!
      </a>
    </div>
  `;
      return;
    }

    // Remove any previous handler to prevent double-firing
    if (current_open_handler) {
      document.removeEventListener("cover-opened", current_open_handler);
      current_open_handler = null;

    }

    // Clear any existing animations
    const existing_congrats = document.querySelector(".congrats-animation");
    if (existing_congrats) {
      existing_congrats.remove();
    }
    const existing_rays = document.querySelector(".light-rays");
    if (existing_rays) {
      existing_rays.remove();
    }

    const click = new Audio('assets/sound-effects/buy.mp3');
    click.currentTime = 0.095;
    click.play();

    const new_card = generate_random_card();
    const updated_card = add_or_update_card(new_card);

    // Update pity counters after card generation
    update_pity_counters(new_card.rarity);

    generate_btn.disabled = true;

    result_display.innerHTML = "click to open [O]";

    // Update container background immediately
    update_container_rarity(updated_card.rarity);


    display_card(updated_card);
    update_points(-COST);
    update_points_display();

    // Create handler for this card
    current_open_handler = function handler() {
      cover_opened = true;

      // Show congratulations animation
      show_congrats_animation(updated_card.rarity);

      // Create another set of light rays on reveal
      create_light_rays(updated_card.rarity);

      if (updated_card.quantity === 1) {
        const rarity_span = updated_card.rarity === 'special-edition'
          ? `<span style="color: #FFD700; font-weight: 900; text-shadow: 2px 2px 0 #000, -2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, 2px 0 0 #000, -2px 0 0 #000, 0 2px 0 #000, 0 -2px 0 #000, 0 0 20px #FF006E, 0 0 40px #00D9FF;">✨ ${updated_card.rarity.toUpperCase()} ✨</span>`
          : `<span style="color: ${get_rarity_display_color(updated_card.rarity)}; font-weight: 900; text-shadow: 2px 2px 0 #000, -2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, 2px 0 0 #000, -2px 0 0 #000, 0 2px 0 #000, 0 -2px 0 #000;">${updated_card.rarity.toUpperCase()}</span>`;

        result_display.innerHTML =
          `🎉 New card unlocked: You got a ${rarity_span} "${updated_card.name}"<br>click to flip [F]`;
      }
      else {
        const rarity_span = updated_card.rarity === 'special-edition'
          ? `<span style="color: #FFD700; font-weight: 900; text-shadow: 2px 2px 0 #000, -2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, 2px 0 0 #000, -2px 0 0 #000, 0 2px 0 #000, 0 -2px 0 #000, 0 0 20px #FF006E, 0 0 40px #00D9FF;">✨ ${updated_card.rarity.toUpperCase()} ✨</span>`
          : `<span style="color: ${get_rarity_display_color(updated_card.rarity)}; font-weight: 900; text-shadow: 2px 2px 0 #000, -2px -2px 0 #000, 2px -2px 0 #000, -2px 2px 0 #000, 2px 0 0 #000, -2px 0 0 #000, 0 2px 0 #000, 0 -2px 0 #000;">${updated_card.rarity.toUpperCase()}</span>`;

        result_display.innerHTML =
          `🎉 You got a ${rarity_span} "${updated_card.name}" (Total owned: ${updated_card.quantity})<br>click to flip [F]`;
      }
      result_display.style.visibility = "visible";

      if (updated_card.rarity == 'epic') {
        const audio = new Audio('assets/sound-effects/lucky-draw1.mp3');
        audio.currentTime = 0;
        audio.play();
      }
      else if (updated_card.rarity == 'legendary' || updated_card.rarity == 'special-edition') {
        const audio = new Audio('assets/sound-effects/lucky-draw2.mp3');
        audio.currentTime = 0;
        audio.play();
      }

      generate_btn.disabled = false;

      // Update guarantee display after revealing
      update_guarantee_display();

      // Remove listener so it only triggers once per open
      document.removeEventListener("cover-opened", current_open_handler);
      current_open_handler = null;
    };

    // Wait for the 'cover-opened' event, then reveal result
    document.addEventListener("cover-opened", current_open_handler);
  });

  // Keyboard shortcuts
  document.addEventListener("keydown", function (e) {
    const key = e.key.toLowerCase();
    if (key === 'b') {
      document.getElementById("generate-card")?.click();
    } else if (key === 'o') {
      document.querySelector("pack-cover")?.click();
    } else if ((key === 'f') && (cover_opened === true)) {
      document.querySelector("frog-card")?.click();
    }
  });
}