const ranges = [
    { minRange: 1, maxRange: 2, tag: "Code Card" },
    { minRange: 1, maxRange: 4, tag: "energyCategory" },
    { minRange: 1, maxRange: 8, tag: "Energy" },
    { minRange: 1, maxRange: 8, tag: "Energy , Holofoil" },
    { minRange: 1, maxRange: 66, tag: "Common" },
    { minRange: 1, maxRange: 66, tag: "Common" },
    { minRange: 1, maxRange: 66, tag: "Common" },
    { minRange: 1, maxRange: 66, tag: "Common" },
    { minRange: 1, maxRange: 66, tag: "Common" },
    { minRange: 1, maxRange: 62, tag: "Uncommon" },
    { minRange: 1, maxRange: 62, tag: "Uncommon" },
    { minRange: 1, maxRange: 62, tag: "Uncommon" },
    { minRange: 1, maxRange: 10, tag: "reverseHoloCategory" },
    { minRange: 1, maxRange: 66, tag: "Common , Reverse Holofoil" },
    { minRange: 1, maxRange: 62, tag: "Uncommon , Reverse Holofoil" },
    { minRange: 1, maxRange: 25, tag: "Rare , Reverse Holofoil" },
    { minRange: 1, maxRange: 10000, tag: "rareCategory" },
    { minRange: 1, maxRange: 25, tag: "Rare , Holofoil" },
    { minRange: 1, maxRange: 12, tag: "Double Rare" },
    { minRange: 1, maxRange: 16, tag: "Ultra Rare" },
    { minRange: 1, maxRange: 16, tag: "Illustration Rare" },
    { minRange: 1, maxRange: 7, tag: "Special Illustration Rare" },
    { minRange: 1, maxRange: 3, tag: "Hyper Rare" },
    { minRange: 1, maxRange: 1000, tag: "godPackCategory" },
    { minRange: 1, maxRange: 3, tag: "godContentsCategory" },
];

function incrementNonce(nonce, offset) {
  let seconds = parseInt(nonce.slice(0, 2), 10);
  let minutes = parseInt(nonce.slice(2, 4), 10);
  let hours = parseInt(nonce.slice(4, 6), 10);
  let day = parseInt(nonce.slice(6, 8), 10);
  let month = parseInt(nonce.slice(8, 10), 10);
  let year = parseInt(nonce.slice(10, 14), 10);

  seconds += offset;
  while (seconds > 59) {
    seconds -= 60;
    minutes += 1;
    if (minutes > 59) {
      minutes = 0;
      hours += 1;
      if (hours > 23) {
        hours = 0;
        day += 1;
        const daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
        if (day > daysInMonth[month - 1]) {
          day = 1;
          month += 1;
          if (month > 12) {
            month = 1;
            year += 1;
          }
        }
      }
    }
  }

  return (
    seconds.toString().padStart(2, '0') +
    minutes.toString().padStart(2, '0') +
    hours.toString().padStart(2, '0') +
    day.toString().padStart(2, '0') +
    month.toString().padStart(2, '0') +
    year.toString().padStart(4, '0')
  );
}

async function generateHmacSha512(key, message) {
  const keyBuffer = new TextEncoder().encode(key);
  const msgBuffer = new TextEncoder().encode(message);
  const cryptoKey = await crypto.subtle.importKey(
    "raw",
    keyBuffer,
    { name: "HMAC", hash: "SHA-512" },
    false,
    ["sign"]
  );
  const signature = await crypto.subtle.sign("HMAC", cryptoKey, msgBuffer);
  return new Uint8Array(signature);
}

async function generateRandomNumbers(ranges, serverSeed, clientSeed, nonce) {
  const randomNumbers = [];
  const numbersPerDigest = 16;
  const digestsNeeded = Math.ceil(ranges.length / numbersPerDigest);

  for (let digestIndex = 0; digestIndex < digestsNeeded; digestIndex++) {
    const message = `${clientSeed}:${nonce}:${digestIndex}`;
    const digest = await generateHmacSha512(serverSeed, message);
    let offset = 0;

    for (let i = 0; i < numbersPerDigest && randomNumbers.length < ranges.length; i++) {
      const range = ranges[randomNumbers.length];
      const bytes = digest.slice(offset, offset + 4);
      const view = new DataView(bytes.buffer, bytes.byteOffset, 4);
      const num = view.getUint32(0, false); // Big-endian
      const rand = Math.floor((num / 0x100000000) * (range.maxRange - range.minRange + 1)) + range.minRange;
      randomNumbers.push(rand);
      offset += 4;
    }
  }

  return randomNumbers;
}

async function mapTaggedResults(randomNumbers, ranges, serverSeed, clientSeed, nonce) {
  const seenValues = {};
  const taggedResults = [];

  for (let index = 0; index < randomNumbers.length; index++) {
    if (!ranges[index]) {
      console.error(`No range found for index ${index}`);
      continue;
    }

    const { tag = "UNKNOWN", minRange, maxRange } = ranges[index];
    let finalNumber = randomNumbers[index];
    let nonceOffset = 0;

    if (!seenValues[tag]) {
      seenValues[tag] = new Set();
    }

    while (seenValues[tag].has(finalNumber.toString())) {
      nonceOffset++;
      const newNonce = incrementNonce(nonce, nonceOffset);
      const message = `${clientSeed}:${newNonce}`;
      const digest = await generateHmacSha512(serverSeed, message);
      const bytes = digest.slice(0, 4);
      const view = new DataView(bytes.buffer, bytes.byteOffset, 4);
      const newNum = view.getUint32(0, false); // Big-endian
      finalNumber = Math.floor((newNum / 0x100000000) * (maxRange - minRange + 1)) + minRange;
    }

    seenValues[tag].add(finalNumber.toString());
    taggedResults.push({ value: finalNumber.toString(), tag });
  }

  return taggedResults;
}

async function filterResults(taggedResults, ranges) {
    let filteredResults = [];
    const codeCard = taggedResults.find((item) => item.tag === "Code Card");
    if (codeCard) filteredResults.push(codeCard);
    const energyCategoryItem = taggedResults.find((item) => item.tag === "energyCategory");
    if (energyCategoryItem) {
        const energyCategoryNum = parseInt(energyCategoryItem.value, 10);
        if (energyCategoryNum >= 1 && energyCategoryNum <= 3) {
            const basicEnergy = taggedResults.find((item) => item.tag === "Energy");
            if (basicEnergy) filteredResults.push(basicEnergy);
        } else if (energyCategoryNum === 4) {
            const holofoilEnergy = taggedResults.find((item) => item.tag === "Energy , Holofoil");
            if (holofoilEnergy) filteredResults.push(holofoilEnergy);
        }
    }
    const commonCards = taggedResults.filter((item) => item.tag === "Common");
    filteredResults.push(...commonCards.splice(0, 5));

    const uncommonCards = taggedResults.filter((item) => item.tag === "Uncommon");
    filteredResults.push(...uncommonCards.splice(0, 3));

    const reverseHoloCategoryItem = taggedResults.find((item) => item.tag === "reverseHoloCategory");
    if (reverseHoloCategoryItem) {
        const reverseHoloCategoryNum = parseInt(reverseHoloCategoryItem.value, 10);
        if (reverseHoloCategoryNum >= 1 && reverseHoloCategoryNum <= 6) {
            const commonReverseHolo = taggedResults.find((item) => item.tag === "Common , Reverse Holofoil");
            if (commonReverseHolo) filteredResults.push(commonReverseHolo);
        } else if (reverseHoloCategoryNum >= 7 && reverseHoloCategoryNum <= 9) {
            const uncommonReverseHolo = taggedResults.find((item) => item.tag === "Uncommon , Reverse Holofoil");
            if (uncommonReverseHolo) filteredResults.push(uncommonReverseHolo);
        } else if (reverseHoloCategoryNum === 10) {
            const rareReverseHolo = taggedResults.find((item) => item.tag === "Rare , Reverse Holofoil");
            if (rareReverseHolo) filteredResults.push(rareReverseHolo);
        }
    }
    const rareCategoryItem = taggedResults.find((item) => item.tag === "rareCategory");
    if (rareCategoryItem) {
        const rareCategoryNum = parseInt(rareCategoryItem.value, 10);
        if (rareCategoryNum >= 1 && rareCategoryNum <= 6673) {
            const rareCard = taggedResults.find((item) => item.tag === "Rare , Holofoil");
            if (rareCard) filteredResults.push(rareCard);
        } else if (rareCategoryNum >= 6674 && rareCategoryNum <= 8001) {
            const rareCard = taggedResults.find((item) => item.tag === "Double Rare");
            if (rareCard) filteredResults.push(rareCard);
        } else if (rareCategoryNum >= 8002 && rareCategoryNum <= 8645) {
            const rareCard = taggedResults.find((item) => item.tag === "Ultra Rare");
            if (rareCard) filteredResults.push(rareCard);
        } else if (rareCategoryNum >= 8646 && rareCategoryNum <= 9495) {
            const rareCard = taggedResults.find((item) => item.tag === "Illustration Rare");
            if (rareCard) filteredResults.push(rareCard);
        } else if (rareCategoryNum >= 9496 && rareCategoryNum <= 9806) {
            const rareCard = taggedResults.find((item) => item.tag === "Special Illustration Rare");
            if (rareCard) filteredResults.push(rareCard);
        } else if (rareCategoryNum >= 9807 && rareCategoryNum <= 10000) {
            const rareCard = taggedResults.find((item) => item.tag === "Hyper Rare");
            if (rareCard) filteredResults.push(rareCard);
        }
    }

    const godPackCategoryItem = taggedResults.find((item) => item.tag === "godPackCategory");
    const isGodPack = godPackCategoryItem && parseInt(godPackCategoryItem.value, 10) === 1000;

    if (isGodPack) {
        const godContentsItem = taggedResults.find((item) => item.tag === "godContentsCategory");
        const godContentsNum = godContentsItem ? parseInt(godContentsItem.value, 10) : 0;

        let lastThreeCards = [];
        if (godContentsNum === 1) {
            lastThreeCards = [
                { value: "3", tag: "Illustration Rare" },
                { value: "4", tag: "Illustration Rare" },
                { value: "2", tag: "Special Illustration Rare" }
            ];
        } else if (godContentsNum === 2) {
            lastThreeCards = [
                { value: "5", tag: "Illustration Rare" },
                { value: "6", tag: "Illustration Rare" },
                { value: "3", tag: "Special Illustration Rare" }
            ];
        } else if (godContentsNum === 3) {
            lastThreeCards = [
                { value: "1", tag: "Illustration Rare" },
                { value: "2", tag: "Illustration Rare" },
                { value: "1", tag: "Special Illustration Rare" }
            ];
        }

        if (lastThreeCards.length > 0) {
            filteredResults = filteredResults.slice(0, Math.max(0, filteredResults.length - 3));
            filteredResults.push(...lastThreeCards);
        }
    }

    return filteredResults;
}
async function setData(serverSeed, clientSeed, nonce) {
  const randomNumbers = await generateRandomNumbers(ranges, serverSeed, clientSeed, nonce);
  const taggedResults = await mapTaggedResults(randomNumbers, ranges, serverSeed, clientSeed, nonce);
  const filteredResults = await filterResults(taggedResults, ranges, serverSeed, clientSeed, nonce);

  return {
    success: true,
    result: filteredResults,
    nonce,
    serverSeed,
    clientSeed
  };
}
export { setData, ranges};
// Example usage with provided inputs
// (async () => {
//   try {
//     const result = await setData(
//       "c7218df4e5de3976b378857ab0ae665662230192b7c459477145168ecaddc877",
//       "maddy",
//       "54340231072025"
//     );
//     console.log(JSON.stringify(result, null, 2));
//   } catch (error) {
//     console.error("Error generating pack:", error);
//   }
// })();
