const ranges = [
    { minRange: 1, maxRange: 73, tag: "Common" },
    { minRange: 1, maxRange: 73, tag: "Common" },
    { minRange: 1, maxRange: 73, tag: "Common" },
    { minRange: 1, maxRange: 73, tag: "Common" },
    { minRange: 1, maxRange: 73, tag: "Common" },
    { minRange: 1, maxRange: 73, tag: "Common" },
    { minRange: 1, maxRange: 54, tag: "Uncommon" },
    { minRange: 1, maxRange: 54, tag: "Uncommon" },
    { minRange: 1, maxRange: 54, tag: "Uncommon" },
    { minRange: 1, maxRange: 13, tag: "rare1Category" },
    { minRange: 1, maxRange: 48, tag: "Rare , Normal" },
    { minRange: 1, maxRange: 18, tag: "Super Rare , Normal" },
    { minRange: 1, maxRange: 12, tag: "Legendary , Normal" },
    { minRange: 1, maxRange: 13, tag: "rare2Category" },
    { minRange: 1, maxRange: 48, tag: "Rare , Normal" },
    { minRange: 1, maxRange: 18, tag: "Super Rare , Normal" },
    { minRange: 1, maxRange: 12, tag: "Legendary , Normal" },
    { minRange: 1, maxRange: 100, tag: "foilCategory" },
    { minRange: 1, maxRange: 73, tag: "Common , Cold Foil" },
    { minRange: 1, maxRange: 55, tag: "Uncommon , Cold Foil" },
    { minRange: 1, maxRange: 48, tag: "Rare , Cold Foil" },
    { minRange: 1, maxRange: 18, tag: "Super Rare , Cold Foil" },
    { minRange: 1, maxRange: 12, tag: "Legendary , Cold Foil" },
    { minRange: 1, maxRange: 12, tag: "Enchanted , Holofoil" },
];

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, serverSeed, clientSeed, nonce) {
  let filteredResults = [];
  let nonceOffset = 0;

  const commons = taggedResults.filter(item => item.tag === "Common").slice(0, 6);
  filteredResults.push(...commons);

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

  const rare1Cat = parseInt(taggedResults.find(item => item.tag === "rare1Category")?.value || "1", 10);
  let rare1Item = null;
  let rare1Tag = null;
  if (rare1Cat >= 1 && rare1Cat <= 9) {
    rare1Item = taggedResults.find(item => item.tag === "Rare , Normal");
    rare1Tag = "Rare , Normal";
  } else if (rare1Cat >= 10 && rare1Cat <= 12) {
    rare1Item = taggedResults.find(item => item.tag === "Super Rare , Normal");
    rare1Tag = "Super Rare , Normal";
  } else if (rare1Cat === 13) {
    rare1Item = taggedResults.find(item => item.tag === "Legendary , Normal");
    rare1Tag = "Legendary , Normal";
  }
  if (rare1Item) filteredResults.push(rare1Item);

  const rare2Cat = parseInt(taggedResults.find(item => item.tag === "rare2Category")?.value || "1", 10);
  let rare2Item = null;
  let rare2Tag = null;
  if (rare2Cat >= 1 && rare2Cat <= 9) {
    rare2Tag = "Rare , Normal";
    rare2Item = taggedResults.find(item => item.tag === "Rare , Normal");
  } else if (rare2Cat >= 10 && rare2Cat <= 12) {
    rare2Tag = "Super Rare , Normal";
    rare2Item = taggedResults.find(item => item.tag === "Super Rare , Normal");
  } else if (rare2Cat === 13) {
    rare2Tag = "Legendary , Normal";
    rare2Item = taggedResults.find(item => item.tag === "Legendary , Normal");
  }

  if (rare1Item && rare2Item && rare1Tag === rare2Tag && rare1Item.value === rare2Item.value) {
    const rangeForTag = ranges.find(range => range.tag === rare2Tag);
    if (rangeForTag) {
      const { minRange, maxRange } = rangeForTag;
      let newValue;
      do {
        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
        newValue = Math.floor((newNum / 0x100000000) * (maxRange - minRange + 1)) + minRange;
      } while (newValue.toString() === rare1Item.value);

      rare2Item = { value: newValue.toString(), tag: rare2Tag };
    }
  }
  if (rare2Item) filteredResults.push(rare2Item);

  const foilCategory = parseInt(taggedResults.find(item => item.tag === "foilCategory")?.value || "1", 10);
  if (foilCategory >= 1 && foilCategory <= 52) {
    const commonFoil = taggedResults.find(item => item.tag === "Common , Cold Foil");
    if (commonFoil) filteredResults.push(commonFoil);
  } else if (foilCategory >= 53 && foilCategory <= 78) {
    const uncommonFoil = taggedResults.find(item => item.tag === "Uncommon , Cold Foil");
    if (uncommonFoil) filteredResults.push(uncommonFoil);
  } else if (foilCategory >= 79 && foilCategory <= 92) {
    const rareFoil = taggedResults.find(item => item.tag === "Rare , Cold Foil");
    if (rareFoil) filteredResults.push(rareFoil);
  } else if (foilCategory >= 93 && foilCategory <= 97) {
    const superRareFoil = taggedResults.find(item => item.tag === "Super Rare , Cold Foil");
    if (superRareFoil) filteredResults.push(superRareFoil);
  } else if (foilCategory >= 98 && foilCategory <= 99) {
    const legendaryFoil = taggedResults.find(item => item.tag === "Legendary , Normal");
    if (legendaryFoil) filteredResults.push(legendaryFoil);
  } else if (foilCategory === 100) {
    const enchantedFoil = taggedResults.find(item => item.tag === "Enchanted , Holofoil");
    if (enchantedFoil) filteredResults.push(enchantedFoil);
  }

  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);
//   }
// })();
