#!/usr/bin/env node
"use strict";
const fs = require("fs");
const path = require("path");
const { Connection, Keypair, SystemProgram, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js");
const {
  TOKEN_2022_PROGRAM_ID,
  ExtensionType,
  getMintLen,
  createInitializeMintInstruction,
  createInitializePermanentDelegateInstruction,
  createInitializeNonTransferableMintInstruction,
  createSetAuthorityInstruction,
  AuthorityType,
} = require("@solana/spl-token");
const { parseEnvConfig, resolveConfigPath, loadKeypair, clusterUrl, nowStamp, PublicKey } = require("./js_common");

async function main() {
  const cfg = parseEnvConfig(resolveConfigPath(process.argv[2]));
  const conn = new Connection(clusterUrl(cfg.CLUSTER), "confirmed");
  const main = loadKeypair(path.resolve(__dirname, cfg.MAIN_KEYPAIR));
  const governance = new PublicKey(cfg.GOVERNANCE);
  const mint = Keypair.generate();
  const mintLen = getMintLen([ExtensionType.NonTransferable, ExtensionType.PermanentDelegate]);
  const rentMint = await conn.getMinimumBalanceForRentExemption(mintLen, "confirmed");
  const tx = new Transaction().add(
    SystemProgram.createAccount({ fromPubkey: main.publicKey, newAccountPubkey: mint.publicKey, space: mintLen, lamports: rentMint, programId: TOKEN_2022_PROGRAM_ID }),
    createInitializeNonTransferableMintInstruction(mint.publicKey, TOKEN_2022_PROGRAM_ID),
    createInitializePermanentDelegateInstruction(mint.publicKey, main.publicKey, TOKEN_2022_PROGRAM_ID),
    createInitializeMintInstruction(mint.publicKey, 0, main.publicKey, main.publicKey, TOKEN_2022_PROGRAM_ID),
    createSetAuthorityInstruction(mint.publicKey, main.publicKey, AuthorityType.MintTokens, governance, [], TOKEN_2022_PROGRAM_ID),
    createSetAuthorityInstruction(mint.publicKey, main.publicKey, AuthorityType.FreezeAccount, governance, [], TOKEN_2022_PROGRAM_ID),
    createSetAuthorityInstruction(mint.publicKey, main.publicKey, AuthorityType.PermanentDelegate, governance, [], TOKEN_2022_PROGRAM_ID)
  );
  const sig = await sendAndConfirmTransaction(conn, tx, [main, mint], { commitment: "confirmed" });
  const runs = path.resolve(__dirname, cfg.RUNS_DIR || "./runs");
  fs.mkdirSync(runs, { recursive: true });
  const rp = path.join(runs, `${nowStamp()}_empty_nft_template.json`);
  fs.writeFileSync(rp, JSON.stringify({ mint: mint.publicKey.toBase58(), tx: sig, createdAt: new Date().toISOString() }, null, 2));
  console.log("EMPTY NFT template created");
  console.log("mint:", mint.publicKey.toBase58());
  console.log("report:", rp);
}
main().catch((e)=>{console.error(e?.message||e);process.exit(1);});
