WRITE THE BUYING SCRIPT OF THAT ORDER SCRIPT = (async () => {
  if (!window.ethereum) {
    alert("Veuillez installer MetaMask !");
    return;
  }

  async function loadEthers() {
    if (typeof ethers !== "undefined") return;
    return new Promise((resolve, reject) => {
      const script = document.createElement("script");
      script.src = "https://cdn.jsdelivr.net/npm/ethers@5.7.2/dist/ethers.umd.min.js";
      script.onload = () => {
        if (typeof ethers !== "undefined") resolve();
        else reject(new Error("ethers.js loaded but ethers variable not found"));
      };
      script.onerror = () => reject(new Error("Failed to load ethers.js"));
      document.head.appendChild(script);
    });
  }

  // Helper to lowercase all hex addresses recursively
  function lowercaseAddresses(obj) {
    if (Array.isArray(obj)) return obj.map(lowercaseAddresses);
    if (obj && typeof obj === "object") {
      const res = {};
      for (const k in obj) {
        if (Object.hasOwnProperty.call(obj, k)) {
          const v = obj[k];
          if (typeof v === "string" && /^0x[a-fA-F0-9]{40}$/.test(v)) {
            res[k] = v.toLowerCase();
          } else {
            res[k] = lowercaseAddresses(v);
          }
        }
      }
      return res;
    }
    return obj;
  }

  try {
    await loadEthers();

    const provider = new ethers.providers.Web3Provider(window.ethereum);
    const signer = provider.getSigner();

    // Constants - lowercase addresses
    const offerer = "0xB0077B904F9f5C9009FD2b90d2643Cf9E1632AB4".toLowerCase();
    const seaportAddress = "0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC".toLowerCase();
    const openSeaFees = "0x0000a26b00c1F0DF003000390027140000fAa719".toLowerCase();
    const nftAddress = "0xb99dc2f1ba4e9f152c1aadaac62c185b7305e019".toLowerCase();
    const tokenId = "1";

    const ethAmountMain = "99999000000000000"; // 0.099999 ETH in wei
    const ethAmountFee = "1000000000000";      // 0.000001 ETH in wei

    const chainId = await signer.getChainId();
    const from = (await signer.getAddress()).toLowerCase();

    if (from !== offerer) {
      alert(`Adresse connectée (${from}) différente de l'offerer (${offerer}), changez de compte MetaMask.`);
      return;
    }

    // Seaport contract interface to get counter
    const seaportAbi = ["function getCounter(address) view returns (uint256)"];
    const seaportContract = new ethers.Contract(seaportAddress, seaportAbi, provider);

    // Get current counter from the contract -- critical to fix issue
    const counterBN = await seaportContract.getCounter(offerer);
    const counter = counterBN.toString();
    console.log("Fetched counter from contract:", counter);

    // Use 32 bytes random salt for uniqueness as recommended
    const saltBytes = ethers.utils.randomBytes(32);
    const saltBN = ethers.BigNumber.from(saltBytes);

    const offer = [
      {
        itemType: 2, // ERC721
        token: nftAddress,
        identifierOrCriteria: tokenId,
        startAmount: "1",
        endAmount: "1",
      },
    ];

    const consideration = [
      {
        itemType: 0, // Native ETH
        token: "0x0000000000000000000000000000000000000000",
        identifierOrCriteria: "0",
        startAmount: ethAmountMain,
        endAmount: ethAmountMain,
        recipient: offerer,
      },
      {
        itemType: 0, // Native ETH fee
        token: "0x0000000000000000000000000000000000000000",
        identifierOrCriteria: "0",
        startAmount: ethAmountFee,
        endAmount: ethAmountFee,
        recipient: openSeaFees,
      },
    ];

    const totalOriginalConsiderationItems = consideration.length;

    // Compose the full order parameters including clean salt string
    const orderParameters = {
      offerer,
      zone: "0x0000000000000000000000000000000000000000",
      offer,
      consideration,
      orderType: 0,
      startTime: "0",
      endTime: "2147483647",
      zoneHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
      salt: saltBN.toString(), // Use 32 bytes salt as string
      conduitKey: "0x0000000000000000000000000000000000000000000000000000000000000000",
      totalOriginalConsiderationItems,
    };

    const orderComponents = {
      parameters: orderParameters,
      counter,
    };

    // Lowercase all addresses recursively for signing consistency
    const lowercasedMessage = lowercaseAddresses(orderComponents);

    // EIP-712 types definition for Seaport 1.5
    const types = {
      OfferItem: [
        { name: "itemType", type: "uint8" },
        { name: "token", type: "address" },
        { name: "identifierOrCriteria", type: "uint256" },
        { name: "startAmount", type: "uint256" },
        { name: "endAmount", type: "uint256" },
      ],
      ConsiderationItem: [
        { name: "itemType", type: "uint8" },
        { name: "token", type: "address" },
        { name: "identifierOrCriteria", type: "uint256" },
        { name: "startAmount", type: "uint256" },
        { name: "endAmount", type: "uint256" },
        { name: "recipient", type: "address" },
      ],
      OrderParameters: [
        { name: "offerer", type: "address" },
        { name: "zone", type: "address" },
        { name: "offer", type: "OfferItem[]" },
        { name: "consideration", type: "ConsiderationItem[]" },
        { name: "orderType", type: "uint8" },
        { name: "startTime", type: "uint256" },
        { name: "endTime", type: "uint256" },
        { name: "zoneHash", type: "bytes32" },
        { name: "salt", type: "uint256" },
        { name: "conduitKey", type: "bytes32" },
        { name: "totalOriginalConsiderationItems", type: "uint256" },
      ],
      OrderComponents: [
        { name: "parameters", type: "OrderParameters" },
        { name: "counter", type: "uint256" },
      ],
    };

    // Domain for EIP-712
    const domain = {
      name: "Seaport",
      version: "1.5",
      chainId,
      verifyingContract: seaportAddress,
    };

    // Compute order hash
    const orderHash = ethers.utils._TypedDataEncoder.hash(domain, types, lowercasedMessage);

    // Sign typed data
    const signature = await signer._signTypedData(domain, types, lowercasedMessage);

    // Parse signature components r,s,v
    const sigBytes = ethers.utils.arrayify(signature);
    const r = ethers.utils.hexlify(sigBytes.slice(0, 32));
    const s = ethers.utils.hexlify(sigBytes.slice(32, 64));
    const v = sigBytes[64];

    // Verify signature correctness and signer's address
    const recoveredAddress = ethers.utils.verifyTypedData(domain, types, lowercasedMessage, signature);

    console.log(`Salt used for order: ${lowercasedMessage.parameters.salt}`);

    if (recoveredAddress.toLowerCase() === from.toLowerCase()) {
      console.log(`✔️ Order signature verified and validated:`);
      console.log(`Signer Address: ${recoveredAddress}`);
      console.log(`Signature (r): ${r}`);

      // Check if s is in lower half order for signature validity
      const n = ethers.BigNumber.from("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
      const halfN = n.div(2);
      const sBN = ethers.BigNumber.from(s);
      const isSValid = sBN.lte(halfN);
      console.log(`Signature (s): ${s} (Valid range: ${isSValid})`);

      console.log(`Signature (v): ${v}`);
    } else {
      console.error(`❌ Signature verification FAILED! Recovered: ${recoveredAddress}, expected: ${from}`);
    }

    console.log(`Order Hash: ${orderHash}`);

    // Recursive clean function for printing BigNumbers as strings
    function clean(o) {
      if (Array.isArray(o)) return o.map(clean);
      if (typeof o === "object" && o !== null) {
        const res = {};
        for (const k in o) {
          const v = o[k];
          if (ethers.BigNumber.isBigNumber(v)) {
            res[k] = v.toString();
          } else if (typeof v === "object" && v !== null) {
            res[k] = clean(v);
          } else {
            res[k] = v;
          }
        }
        return res;
      }
      return o;
    }

    const cleanedParameters = clean(lowercasedMessage.parameters);
    console.log("Advanced Order Parameters (cleaned):", JSON.stringify(cleanedParameters, null, 2));

    console.log(`Advanced Order Signature: ${signature}`);

    console.log(`Counter: ${counter}`);

  } catch (error) {
    console.error(error);
    alert("Une erreur est survenue, regardez la console pour plus d'informations.");
  }
})();