'use strict';

const { Keypair, Connection, PublicKey } = require('@solana/web3.js');
// bs58 v6 is ESM-first: under CommonJS it exports ONLY { default }, so a bare
// require('bs58') yields an object whose .encode/.decode are undefined. That
// failed at runtime while every unit test passed, because the tests used fakes
// and never touched this path. Keep the .default — and see the regression test
// in test/bs58.test.js that exercises it for real.
const bs58 = require('bs58').default;

/**
 * Local wallet loading.
 *
 * HARD INVARIANT (TECH_SPEC_V5 §2, NFR-16): the private key never leaves this
 * machine. It is read from the operator's own .env, held in memory for signing,
 * and never logged, never sent anywhere, never written to disk by this process,
 * and never exposed over the dashboard, the relay, or Telegram.
 *
 * If you are about to add a console.log, a telemetry field, or a dashboard
 * value that touches the secret key: don't. There is no legitimate reason.
 */

function loadWallet(env = process.env) {
  const raw = env.PRIVATE_KEY;
  if (!raw || !raw.trim()) {
    throw new Error(
      'PRIVATE_KEY is not set. Add it to your .env file. ' +
        'It never leaves this machine — see README.'
    );
  }

  let keypair;
  const trimmed = raw.trim();
  try {
    if (trimmed.startsWith('[')) {
      // JSON byte array, as emitted by `solana-keygen`.
      const bytes = Uint8Array.from(JSON.parse(trimmed));
      keypair = Keypair.fromSecretKey(bytes);
    } else {
      // base58, as exported by Phantom and most wallet UIs.
      keypair = Keypair.fromSecretKey(bs58.decode(trimmed));
    }
  } catch (err) {
    // Deliberately does NOT include `raw` or `err.message` in the thrown text —
    // a malformed key must not leak fragments of itself into logs.
    throw new Error(
      'PRIVATE_KEY could not be parsed. Expected a base58 string or a JSON byte ' +
        'array. The value itself is not logged.'
    );
  }

  return keypair;
}

function createConnection(env = process.env) {
  const url = env.RPC_URL;
  if (!url || !url.trim()) {
    throw new Error(
      'RPC_URL is not set. A public mainnet RPC will rate-limit this bot almost ' +
        'immediately — use your own provider endpoint. See .env.example.'
    );
  }
  return new Connection(url.trim(), 'confirmed');
}

/** Public address only. This is the sole wallet value any surface may display. */
function publicAddress(keypair) {
  return keypair.publicKey.toBase58();
}

async function getSolBalance(connection, keypair) {
  const lamports = await connection.getBalance(new PublicKey(publicAddress(keypair)));
  return lamports / 1e9;
}

module.exports = { loadWallet, createConnection, publicAddress, getSolBalance };
