#!/usr/bin/env node
"use strict";

const fs = require("fs");
const path = require("path");
const BN = require("bn.js");
const { Connection, Keypair, PublicKey, Transaction, sendAndConfirmTransaction, clusterApiUrl } = require("@solana/web3.js");
const {
  PROGRAM_VERSION_V3,
  InstructionData,
  AccountMetaData,
  withRevokeGoverningTokens,
  withExecuteTransaction,
} = require("@solana/spl-governance");

function parseEnvConfig(configPath) {
  const raw = fs.readFileSync(configPath, "utf8");
  const out = {};
  for (const line of raw.split("\n")) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith("#")) continue;
    const eq = trimmed.indexOf("=");
    if (eq === -1) continue;
    const key = trimmed.slice(0, eq).trim();
    let val = trimmed.slice(eq + 1).trim();
    if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
      val = val.slice(1, -1);
    }
    val = val.replace(/\$HOME/g, process.env.HOME || "");
    out[key] = val;
  }
  return out;
}

function loadKeypair(filePath) {
  const arr = JSON.parse(fs.readFileSync(filePath, "utf8"));
  return Keypair.fromSecretKey(Uint8Array.from(arr));
}

function toGovernanceInstructionData(ix) {
  return new InstructionData({
    programId: ix.programId,
    accounts: ix.keys.map(
      (k) =>
        new AccountMetaData({
          pubkey: k.pubkey,
          isSigner: !!k.isSigner,
          isWritable: !!k.isWritable,
        })
    ),
    data: Uint8Array.from(ix.data),
  });
}

async function main() {
  const configPath = process.argv[2] ? path.resolve(process.argv[2]) : path.resolve(__dirname, "dao.config.env");
  const realm = new PublicKey(process.argv[3]);
  const governance = new PublicKey(process.argv[4]);
  const proposal = new PublicKey(process.argv[5]);
  const proposalTx = new PublicKey(process.argv[6]);
  const mint = new PublicKey(process.argv[7]);
  const targetOwner = new PublicKey(process.argv[8]);
  const amount = new BN(process.argv[9] || "1");
  if (!process.argv[8]) {
    throw new Error(
      "Использование: node scripts/dao/execute_revoke_transaction_full_exec.js <config.env> <realm> <governance> <proposal> <proposal_tx> <mint> <target_owner> [amount]"
    );
  }
  const cfg = parseEnvConfig(configPath);
  const cluster = cfg.DAO_CLUSTER || "devnet";
  const governanceProgramId = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID);
  const signer = loadKeypair(path.resolve(cfg.DAO_ISSUER_KEYPAIR));
  const connection = new Connection(clusterApiUrl(cluster), "confirmed");

  const ixRawRevoke = [];
  await withRevokeGoverningTokens(
    ixRawRevoke,
    governanceProgramId,
    PROGRAM_VERSION_V3,
    realm,
    targetOwner,
    mint,
    governance,
    amount
  );
  const revokeInstructionData = toGovernanceInstructionData(ixRawRevoke[0]);

  const ixExecute = [];
  await withExecuteTransaction(
    ixExecute,
    governanceProgramId,
    PROGRAM_VERSION_V3,
    governance,
    proposal,
    proposalTx,
    [revokeInstructionData]
  );
  const sig = await sendAndConfirmTransaction(connection, new Transaction().add(...ixExecute), [signer], {
    commitment: "confirmed",
  });
  console.log("Execute success. Tx:", sig);
}

main().catch((e) => {
  console.error("Ошибка execute revoke:", e?.message || e);
  process.exit(1);
});
