const express = require('express');
const QRCode = require('qrcode');
const { attachWalletUser, requireWalletUser } = require('../middleware/walletUserAuth');
const { EVM_CANDIDATE_CONFIG } = require('../config/evmCandidateConfig');
const evmCandidateNetworkService = require('../services/evmCandidateNetworkService');
const evmWalletService = require('../services/evmWalletService');
const evmOperatorWalletService = require('../services/evmOperatorWalletService');
const evmTransferService = require('../services/evmTransferService');
const multiChainWalletService = require('../services/multiChainWalletService');
const walletCsrfService = require('../services/walletCsrfService');
const {
  SUPPORTED_LANGS,
  buildLangUrl,
  createTranslator,
  errorText,
  localeTag,
  resolveLang
} = require('../services/evmWalletI18n');

const router = express.Router();

router.use(attachWalletUser);
router.use(requireWalletUser);
router.use((req, res, next) => {
  res.set('Cache-Control', 'no-store, no-cache, must-revalidate, private');
  res.set('Pragma', 'no-cache');
  res.set('Expires', '0');
  req.walletLang = resolveLang(req);
  req.walletT = createTranslator(req.walletLang);
  if (req.query.lang) {
    res.cookie('plais_wallet_lang', req.walletLang, {
      httpOnly: true,
      sameSite: 'lax',
      secure: process.env.NODE_ENV === 'production',
      maxAge: 365 * 24 * 60 * 60 * 1000,
      path: '/wallet/evm'
    });
  }
  next();
});

function i18nLocals(req) {
  return {
    lang: req.walletLang,
    languages: SUPPORTED_LANGS,
    langUrl: nextLang => buildLangUrl(req, nextLang),
    localeTag: localeTag(req.walletLang),
    t: req.walletT,
    csrfToken: action => walletCsrfService.createToken(req.walletUser.userId, action)
  };
}

function assertCsrf(req, action) {
  if (!walletCsrfService.verifyToken(req.body.csrfToken, req.walletUser.userId, action)) {
    const error = new Error('Invalid wallet CSRF token.');
    error.status = 403;
    error.code = 'INVALID_WALLET_CSRF';
    throw error;
  }
}

function redirectResult(req, res, pathname, params = {}) {
  const query = new URLSearchParams({ lang: req.walletLang });
  for (const [key, value] of Object.entries(params)) {
    if (value) query.set(key, String(value));
  }
  return res.redirect(`${pathname}?${query.toString()}`);
}

function walletTransactions(plaisTransfers, multiChain, ownAddress) {
  const plais = plaisTransfers.map(transaction => ({
    ...transaction,
    asset: 'PLAIS',
    direction: String(transaction.from).toLowerCase() === String(ownAddress).toLowerCase() ? 'out' : 'in',
    explorerUrl: `/wallet/evm/tx/${encodeURIComponent(transaction.hash)}`
  }));
  const external = multiChain && multiChain.transactions
    ? [...multiChain.transactions.bnb, ...multiChain.transactions.babyDoge, ...multiChain.transactions.trx]
    : [];
  return [...plais, ...external]
    .sort((left, right) => new Date(right.createdAt || 0) - new Date(left.createdAt || 0))
    .slice(0, 80);
}

function requireSuperAdminWalletUser(req, res, next) {
  if (req.walletUser && req.walletUser.isSuperAdmin === true &&
      String(req.walletUser.loginId || req.walletUser.userid || '').toLowerCase() === 'superadmin') {
    return next();
  }
  return res.status(403).send('superadmin only');
}

router.get('/admin', requireSuperAdminWalletUser, async (req, res, next) => {
  try {
    const [network, operatorWallet] = await Promise.all([
      evmCandidateNetworkService.getStatus(),
      evmOperatorWalletService.getOperatorWalletSummary()
    ]);
    const [receiveQr, transfers, multiChain] = operatorWallet.address ? await Promise.all([
      QRCode.toDataURL(operatorWallet.address, { width: 220, margin: 1 }),
      Promise.resolve(evmTransferService.listTransfers(operatorWallet.address, 30)),
      multiChainWalletService.getPortfolio(operatorWallet.address)
    ]) : ['', [], null];
    const tronReceiveQr = multiChain && multiChain.tron.address
      ? await QRCode.toDataURL(multiChain.tron.address, { width: 220, margin: 1 })
      : '';
    return res.render('wallet_evm_admin', {
      ...i18nLocals(req),
      walletUser: req.walletUser,
      network,
      operatorWallet,
      receiveQr,
      tronReceiveQr,
      multiChain,
      transfers,
      walletTransactions: walletTransactions(transfers, multiChain, operatorWallet.address),
      transferResult: Boolean(req.query.sent || req.query.errorCode),
      notice: req.query.sent ? `${req.query.asset || 'PLAIS'} ${req.walletT('transferConfirmed')} ${req.query.sent}` : '',
      error: req.query.errorCode ? errorText({ code: req.query.errorCode }, req.walletT) : '',
      config: EVM_CANDIDATE_CONFIG
    });
  } catch (error) {
    return next(error);
  }
});

async function renderPage(req, res, extra = {}) {
  const wallet = evmWalletService.getWalletByOwner('aisfor_user', req.walletUser.userId);
  const [network, account, receiveQr, multiChain] = await Promise.all([
    evmCandidateNetworkService.getStatus(),
    wallet ? evmTransferService.getAccountSummary(wallet.address) : Promise.resolve(null),
    wallet ? QRCode.toDataURL(wallet.address, { width: 220, margin: 1 }) : Promise.resolve(''),
    wallet ? multiChainWalletService.getPortfolio(wallet.address) : Promise.resolve(null)
  ]);
  const tronReceiveQr = multiChain && multiChain.tron.address
    ? await QRCode.toDataURL(multiChain.tron.address, { width: 220, margin: 1 })
    : '';
  const transfers = wallet ? evmTransferService.listTransfers(wallet.address, 30) : [];
  res.render('wallet_evm', {
    ...i18nLocals(req),
    walletUser: req.walletUser,
    wallet,
    account,
    receiveQr,
    tronReceiveQr,
    multiChain,
    transfers,
    walletTransactions: walletTransactions(transfers, multiChain, wallet ? wallet.address : ''),
    network,
    config: EVM_CANDIDATE_CONFIG,
    transferResult: Boolean(req.query.sent || req.query.errorCode),
    recovery: extra.recovery || null,
    signatureCheck: extra.signatureCheck || null,
    notice: extra.notice || (req.query.sent ? `${req.query.asset || 'PLAIS'} ${req.walletT('transferConfirmed')} ${req.query.sent}` : ''),
    error: extra.error || (req.query.errorCode ? errorText({ code: req.query.errorCode }, req.walletT) : '') || req.query.error || ''
  });
}

router.get('/', (req, res) => {
  if (req.walletUser && req.walletUser.isSuperAdmin === true && req.query.personal !== '1') {
    return res.redirect('/wallet/evm/admin');
  }
  return renderPage(req, res);
});

router.get('/tx/:hash', async (req, res, next) => {
  try {
    const stored = evmTransferService.getStoredTransfer(req.params.hash);
    if (!stored) return res.status(404).send(req.walletT('transactionNotFound'));
    const personalWallet = evmWalletService.getWalletByOwner('aisfor_user', req.walletUser.userId);
    let allowedAddress = personalWallet ? personalWallet.address : '';
    let backUrl = `/wallet/evm?personal=${req.walletUser.isSuperAdmin ? '1' : '0'}&lang=${req.walletLang}`;
    if (req.walletUser.isSuperAdmin) {
      const operatorWallet = await evmOperatorWalletService.getOperatorWalletSummary();
      const operatorAddress = operatorWallet.address || '';
      const operatorInvolved = [stored.from, stored.to].some(value => String(value).toLowerCase() === operatorAddress.toLowerCase());
      if (operatorInvolved) {
        allowedAddress = operatorAddress;
        backUrl = `/wallet/evm/admin?lang=${req.walletLang}`;
      }
    }
    const allowed = [stored.from, stored.to].some(value => String(value).toLowerCase() === String(allowedAddress).toLowerCase());
    if (!allowed) return res.status(403).send('Wallet access denied.');
    const transaction = await evmTransferService.getTransactionDetails(req.params.hash);
    if (!transaction) return res.status(404).send(req.walletT('transactionNotFound'));
    return res.render('wallet_evm_tx', {
      ...i18nLocals(req),
      walletUser: req.walletUser,
      transaction,
      backUrl
    });
  } catch (error) {
    return next(error);
  }
});

router.get('/qr/:address', async (req, res, next) => {
  try {
    const wallet = evmWalletService.getWalletByOwner('aisfor_user', req.walletUser.userId);
    if (!wallet || wallet.address.toLowerCase() !== String(req.params.address).toLowerCase()) {
      return res.status(403).send('Wallet access denied.');
    }
    const svg = await QRCode.toString(wallet.address, { type: 'svg', width: 220, margin: 1 });
    res.type('image/svg+xml').send(svg);
  } catch (error) {
    next(error);
  }
});

router.post('/create', async (req, res) => {
  try {
    assertCsrf(req, 'create');
    const pin = String(req.body.pin || '').trim();
    if (pin !== String(req.body.pinConfirm || '').trim()) {
      return renderPage(req, res, { error: req.walletT('pinMismatch') });
    }
    const result = evmWalletService.createWalletForOwner({
      ownerType: 'aisfor_user',
      ownerId: req.walletUser.userId,
      label: req.body.label || `${req.walletUser.displayName || req.walletUser.userId} PLAIS EVM Wallet`,
      pin
    });
    return renderPage(req, res, {
      recovery: result.recovery,
      notice: result.created ? req.walletT('walletCreated') : req.walletT('walletExists')
    });
  } catch (error) {
    return renderPage(req, res, { error: errorText(error, req.walletT) });
  }
});

router.post('/recovery/export', async (req, res) => {
  try {
    assertCsrf(req, 'recovery');
    const recovery = evmWalletService.exportRecoveryForOwner({
      ownerType: 'aisfor_user',
      ownerId: req.walletUser.userId,
      pin: req.body.pin
    });
    return renderPage(req, res, { recovery, notice: req.walletT('recoveryOpened') });
  } catch (error) {
    return renderPage(req, res, { error: errorText(error, req.walletT) });
  }
});

router.post('/verify-signature', async (req, res) => {
  try {
    assertCsrf(req, 'verify');
    const signatureCheck = await evmWalletService.signMessageForOwner({
      ownerType: 'aisfor_user',
      ownerId: req.walletUser.userId,
      pin: req.body.pin,
      message: `PLAIS wallet ownership verification:${req.walletUser.userId}`
    });
    return renderPage(req, res, {
      signatureCheck,
      notice: signatureCheck.verified ? req.walletT('signatureValid') : req.walletT('signatureFailed')
    });
  } catch (error) {
    return renderPage(req, res, { error: errorText(error, req.walletT) });
  }
});

router.post('/send', async (req, res) => {
  try {
    assertCsrf(req, 'send');
    if (req.body.confirmed !== '1') {
      const error = new Error('Transfer confirmation is required.');
      error.code = 'EVM_TRANSFER_CONFIRMATION_REQUIRED';
      throw error;
    }
    const result = await evmWalletService.sendTransferForOwner({
      ownerType: 'aisfor_user',
      ownerId: req.walletUser.userId,
      pin: req.body.pin,
      to: req.body.to,
      amount: req.body.amount,
      memo: req.body.memo
    });
    return redirectResult(req, res, '/wallet/evm', { personal: req.walletUser.isSuperAdmin ? '1' : '', sent: result.hash });
  } catch (error) {
    return redirectResult(req, res, '/wallet/evm', {
      personal: req.walletUser.isSuperAdmin ? '1' : '',
      errorCode: error.code || 'EVM_TRANSFER_ERROR'
    });
  }
});

router.post('/send/babydoge', async (req, res) => {
  try {
    assertCsrf(req, 'send-babydoge');
    if (req.body.confirmed !== '1') throw Object.assign(new Error('Transfer confirmation is required.'), { code: 'EVM_TRANSFER_CONFIRMATION_REQUIRED' });
    const recovery = evmWalletService.exportRecoveryForOwner({ ownerType: 'aisfor_user', ownerId: req.walletUser.userId, pin: req.body.pin });
    const result = await multiChainWalletService.sendBabyDoge({ privateKey: recovery.privateKey, to: req.body.to, amount: req.body.amount });
    multiChainWalletService.recordTransfer(result);
    return redirectResult(req, res, '/wallet/evm', { personal: req.walletUser.isSuperAdmin ? '1' : '', sent: result.hash, asset: 'BABYDOGE' });
  } catch (error) {
    return redirectResult(req, res, '/wallet/evm', { personal: req.walletUser.isSuperAdmin ? '1' : '', errorCode: error.code || 'MULTICHAIN_TRANSFER_ERROR' });
  }
});

router.post('/send/bnb', async (req, res) => {
  try {
    assertCsrf(req, 'send-bnb');
    if (req.body.confirmed !== '1') throw Object.assign(new Error('Transfer confirmation is required.'), { code: 'EVM_TRANSFER_CONFIRMATION_REQUIRED' });
    const recovery = evmWalletService.exportRecoveryForOwner({ ownerType: 'aisfor_user', ownerId: req.walletUser.userId, pin: req.body.pin });
    const result = await multiChainWalletService.sendBnb({ privateKey: recovery.privateKey, to: req.body.to, amount: req.body.amount });
    multiChainWalletService.recordTransfer(result);
    return redirectResult(req, res, '/wallet/evm', { personal: req.walletUser.isSuperAdmin ? '1' : '', sent: result.hash, asset: 'BNB' });
  } catch (error) {
    return redirectResult(req, res, '/wallet/evm', { personal: req.walletUser.isSuperAdmin ? '1' : '', errorCode: error.code || 'MULTICHAIN_TRANSFER_ERROR' });
  }
});

router.post('/send/trx', async (req, res) => {
  try {
    assertCsrf(req, 'send-trx');
    if (req.body.confirmed !== '1') throw Object.assign(new Error('Transfer confirmation is required.'), { code: 'EVM_TRANSFER_CONFIRMATION_REQUIRED' });
    const recovery = evmWalletService.exportRecoveryForOwner({ ownerType: 'aisfor_user', ownerId: req.walletUser.userId, pin: req.body.pin });
    const result = await multiChainWalletService.sendTrx({ privateKey: recovery.privateKey, to: req.body.to, amount: req.body.amount });
    multiChainWalletService.recordTransfer(result);
    return redirectResult(req, res, '/wallet/evm', { personal: req.walletUser.isSuperAdmin ? '1' : '', sent: result.hash, asset: 'TRX' });
  } catch (error) {
    return redirectResult(req, res, '/wallet/evm', { personal: req.walletUser.isSuperAdmin ? '1' : '', errorCode: error.code || 'MULTICHAIN_TRANSFER_ERROR' });
  }
});

router.post('/admin/send', requireSuperAdminWalletUser, async (req, res) => {
  try {
    assertCsrf(req, 'operator-send');
    if (req.body.confirmed !== '1') {
      const error = new Error('Transfer confirmation is required.');
      error.code = 'EVM_TRANSFER_CONFIRMATION_REQUIRED';
      throw error;
    }
    const result = await evmOperatorWalletService.sendOperatorTransfer({
      to: req.body.to,
      amount: req.body.amount,
      memo: req.body.memo
    });
    return redirectResult(req, res, '/wallet/evm/admin', { sent: result.hash });
  } catch (error) {
    return redirectResult(req, res, '/wallet/evm/admin', { errorCode: error.code || 'EVM_TRANSFER_ERROR' });
  }
});

router.post('/admin/send/babydoge', requireSuperAdminWalletUser, async (req, res) => {
  try {
    assertCsrf(req, 'operator-send-babydoge');
    if (req.body.confirmed !== '1') throw Object.assign(new Error('Transfer confirmation is required.'), { code: 'EVM_TRANSFER_CONFIRMATION_REQUIRED' });
    await evmOperatorWalletService.sendOperatorTransfer();
  } catch (error) {
    return redirectResult(req, res, '/wallet/evm/admin', { errorCode: error.code || 'MULTICHAIN_TRANSFER_ERROR' });
  }
});

router.post('/admin/send/bnb', requireSuperAdminWalletUser, async (req, res) => {
  try {
    assertCsrf(req, 'operator-send-bnb');
    if (req.body.confirmed !== '1') throw Object.assign(new Error('Transfer confirmation is required.'), { code: 'EVM_TRANSFER_CONFIRMATION_REQUIRED' });
    await evmOperatorWalletService.sendOperatorTransfer();
  } catch (error) {
    return redirectResult(req, res, '/wallet/evm/admin', { errorCode: error.code || 'MULTICHAIN_TRANSFER_ERROR' });
  }
});

router.post('/admin/send/trx', requireSuperAdminWalletUser, async (req, res) => {
  try {
    assertCsrf(req, 'operator-send-trx');
    if (req.body.confirmed !== '1') throw Object.assign(new Error('Transfer confirmation is required.'), { code: 'EVM_TRANSFER_CONFIRMATION_REQUIRED' });
    await evmOperatorWalletService.sendOperatorTransfer();
  } catch (error) {
    return redirectResult(req, res, '/wallet/evm/admin', { errorCode: error.code || 'MULTICHAIN_TRANSFER_ERROR' });
  }
});

module.exports = router;
