const http = require('http');
const fs = require('fs');
const crypto = require('crypto');

const config = JSON.parse(fs.readFileSync('/opt/binary/wallets/tron/config.json', 'utf8'));
const privateKey = fs.readFileSync('/opt/binary/wallets/tron/.privkey', 'utf8').trim();
const hmacKeyPath = '/dev/shm/engine_hmac.key';

let tronWeb;
let hmacKey = '';

function loadHmacKey() {
  try { hmacKey = fs.readFileSync(hmacKeyPath, 'utf8').trim(); }
  catch(e) { hmacKey = ''; }
}

function verifyHmac(req, body) {
  if (!hmacKey) loadHmacKey();
  if (!hmacKey) return false;
  const ts = req.headers['x-engine-ts'] || '';
  const nonce = req.headers['x-engine-nonce'] || '';
  const sig = req.headers['x-engine-sig'] || '';
  if (!ts || !nonce || !sig) return false;
  const age = Math.abs(Math.floor(Date.now()/1000) - parseInt(ts, 10));
  if (age > 300) return false;
  const expected = crypto.createHmac('sha256', hmacKey)
    .update(ts + '.' + nonce + '.' + req.method + '.' + req.url + '.' + body)
    .digest('hex');
  return crypto.timingSafeEqual(Buffer.from(sig, 'hex'), Buffer.from(expected, 'hex'));
}

async function init() {
  const mod = require('tronweb');
  const TronWeb = mod.default.TronWeb || mod.TronWeb;
  tronWeb = new TronWeb({
    fullHost: config.fullnode,
    headers: { 'TRON-PRO-API-KEY': config.api_key },
    privateKey: privateKey
  });
  loadHmacKey();
}

const server = http.createServer(async (req, res) => {
  if (req.method !== 'POST') { res.writeHead(405); res.end(); return; }

  let body = '';
  req.on('data', chunk => body += chunk);
  req.on('end', async () => {
    try {
      if (!verifyHmac(req, body)) {
        res.writeHead(401, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ error: 'auth_failed' }));
        return;
      }

      const data = JSON.parse(body);

      if (req.url === '/balance') {
        const contract = await tronWeb.contract().at(config.usdt_contract);
        const balance = await contract.balanceOf(config.wallet_address).call();
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ balance: balance.toString(), decimals: 6 }));

      } else if (req.url === '/transfer') {
        if (!data.to || !data.amount) {
          res.writeHead(400, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify({ error: 'missing to or amount' }));
          return;
        }
        const amt = parseInt(data.amount, 10);
        if (isNaN(amt) || amt <= 0 || amt > 1000000000) {
          res.writeHead(400, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify({ error: 'invalid amount' }));
          return;
        }
        if (typeof data.to !== 'string' || !/^T[1-9A-HJ-NP-Za-km-z]{33}$/.test(data.to)) {
          res.writeHead(400, { 'Content-Type': 'application/json' });
          res.end(JSON.stringify({ error: 'invalid address' }));
          return;
        }
        const contract = await tronWeb.contract().at(config.usdt_contract);
        const tx = await contract.transfer(data.to, amt).send();
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ txid: tx, status: 'sent' }));

      } else if (req.url === '/address') {
        res.writeHead(200, { 'Content-Type': 'application/json' });
        res.end(JSON.stringify({ address: config.wallet_address, network: config.network }));

      } else {
        res.writeHead(404);
        res.end();
      }
    } catch (err) {
      res.writeHead(500, { 'Content-Type': 'application/json' });
      res.end(JSON.stringify({ error: 'internal_error' }));
    }
  });
});

init().then(() => {
  server.listen(config.rpc_port, config.rpc_bind, () => {
    process.stdout.write('tron-signer listening on ' + config.rpc_bind + ':' + config.rpc_port + '\n');
  });
}).catch(err => {
  process.stderr.write('init failed\n');
  process.exit(1);
});
