const SUPPORTED_LANGS = ['ko', 'en', 'zh', 'ja'];
const DEFAULT_LANG = 'ko';

const TEXT = {
  ko: {
    title: 'PLAIS EVM 후보 지갑',
    adminTitle: 'PLAIS EVM 운영 지갑',
    operatorWallet: '운영 지갑',
    personalWallet: '개인 후보 지갑',
    candidateStatus: '후보망 상태',
    network: '네트워크',
    latestBlock: '최근 블록',
    externalTransfer: '외부 전송',
    createTitle: '실제 서명 지갑 생성',
    createDescription: '표준 EVM 주소와 전자서명 키를 생성합니다. 현재는 후보망 검증 전용이며 실제 자산 입금과 외부 출금은 지원하지 않습니다.',
    walletName: '지갑 이름',
    securityPin: '보안 PIN',
    pinConfirm: 'PIN 확인',
    pinPlaceholder: '숫자 6-12자리',
    reenter: '다시 입력',
    createWallet: '후보 지갑 생성',
    copyAddress: '주소 복사',
    copied: '복사됨',
    protocol: '프로토콜',
    created: '생성',
    keyStorage: '키 보관',
    pinEncrypted: 'PIN 암호화',
    signatureTitle: '소유권 서명 검증',
    localVerification: '로컬 검증',
    verifySignature: '전자서명 검증',
    verificationResult: '검증 결과',
    valid: '정상',
    failed: '실패',
    recoveryCheck: '복구정보 확인',
    pinRequired: 'PIN 필요',
    openRecovery: '복구정보 열기',
    recoveryInfo: '복구정보',
    hiddenOnClose: '화면을 닫으면 숨겨짐',
    recoveryWarning: '이 정보가 있으면 누구나 지갑을 통제할 수 있습니다. 메신저, 이메일, 클라우드 메모에 저장하지 마세요.',
    mnemonic: '복구문구',
    copyMnemonic: '복구문구 복사',
    privateKey: '개인키',
    copyPrivateKey: '개인키 복사',
    accountOnly: '계정 전용',
    operatorStatus: '운영 지갑 상태',
    operatorNotConfigured: '운영 지갑 키가 구성되지 않았습니다.',
    errorLabel: '오류',
    ownerAccount: '소유 계정',
    candidateBalance: '후보망 잔액',
    storageMethod: '보관 방식',
    serverVault: '서버 운영 금고',
    operatorKeyHidden: '운영 개인키는 브라우저에 제공되지 않습니다.',
    operatorDescription: '이 화면은 superadmin 계정에 운영 지갑의 조회 권한만 연결합니다. 외부 전송은 현재 {state} 상태입니다.',
    pinMismatch: 'PIN 확인 값이 일치하지 않습니다.',
    walletCreated: 'PLAIS EVM 후보 지갑이 생성되었습니다. 복구문구와 개인키를 안전하게 보관해 주세요.',
    walletExists: '이미 생성된 PLAIS EVM 후보 지갑이 있습니다.',
    recoveryOpened: '복구정보를 확인했습니다. 이 화면을 닫으면 다시 숨겨집니다.',
    signatureValid: '개인키 전자서명 검증에 성공했습니다.',
    signatureFailed: '전자서명 검증에 실패했습니다.',
    invalidPin: 'PIN은 숫자 6-12자리여야 합니다.',
    pinVerificationFailed: 'PIN 확인에 실패했습니다.',
    walletNotFound: 'PLAIS EVM 지갑을 찾을 수 없습니다.',
    walletDisabled: 'PLAIS EVM 후보 지갑 기능이 비활성화되어 있습니다.',
    genericError: '지갑 처리 중 오류가 발생했습니다.'
  },
  en: {
    title: 'PLAIS EVM Candidate Wallet', adminTitle: 'PLAIS EVM Operator Wallet', operatorWallet: 'Operator Wallet', personalWallet: 'Personal Candidate Wallet', candidateStatus: 'Candidate Network Status', network: 'Network', latestBlock: 'Latest Block', externalTransfer: 'External Transfers', createTitle: 'Create a Signing Wallet', createDescription: 'Creates a standard EVM address and signing key. This candidate network is for validation only and does not support real deposits or external withdrawals.', walletName: 'Wallet Name', securityPin: 'Security PIN', pinConfirm: 'Confirm PIN', pinPlaceholder: '6-12 digits', reenter: 'Enter again', createWallet: 'Create Candidate Wallet', copyAddress: 'Copy Address', copied: 'Copied', protocol: 'Protocol', created: 'Created', keyStorage: 'Key Storage', pinEncrypted: 'PIN Encrypted', signatureTitle: 'Ownership Signature Verification', localVerification: 'Local Verification', verifySignature: 'Verify Signature', verificationResult: 'Verification Result', valid: 'Valid', failed: 'Failed', recoveryCheck: 'View Recovery Information', pinRequired: 'PIN Required', openRecovery: 'Open Recovery Information', recoveryInfo: 'Recovery Information', hiddenOnClose: 'Hidden when this page closes', recoveryWarning: 'Anyone with this information can control the wallet. Do not store it in messages, email, or cloud notes.', mnemonic: 'Recovery Phrase', copyMnemonic: 'Copy Recovery Phrase', privateKey: 'Private Key', copyPrivateKey: 'Copy Private Key', accountOnly: 'account only', operatorStatus: 'Operator Wallet Status', operatorNotConfigured: 'The operator wallet key is not configured.', errorLabel: 'Error', ownerAccount: 'Owner Account', candidateBalance: 'Candidate Balance', storageMethod: 'Storage Method', serverVault: 'Server Operator Vault', operatorKeyHidden: 'The operator private key is never sent to the browser.', operatorDescription: 'This page grants the superadmin account read-only access to the operator wallet. External transfers are currently {state}.', pinMismatch: 'The PIN confirmation does not match.', walletCreated: 'Your PLAIS EVM candidate wallet was created. Store the recovery phrase and private key safely.', walletExists: 'A PLAIS EVM candidate wallet already exists.', recoveryOpened: 'Recovery information is displayed. It will be hidden again when this page closes.', signatureValid: 'Private-key signature verification succeeded.', signatureFailed: 'Signature verification failed.', invalidPin: 'The PIN must contain 6-12 digits.', pinVerificationFailed: 'PIN verification failed.', walletNotFound: 'The PLAIS EVM wallet was not found.', walletDisabled: 'The PLAIS EVM candidate wallet is disabled.', genericError: 'An error occurred while processing the wallet.'
  },
  zh: {
    title: 'PLAIS EVM 候选钱包', adminTitle: 'PLAIS EVM 运营钱包', operatorWallet: '运营钱包', personalWallet: '个人候选钱包', candidateStatus: '候选网络状态', network: '网络', latestBlock: '最新区块', externalTransfer: '外部转账', createTitle: '创建签名钱包', createDescription: '创建标准 EVM 地址和电子签名密钥。目前仅用于候选网络验证，不支持真实资产充值或外部提现。', walletName: '钱包名称', securityPin: '安全 PIN', pinConfirm: '确认 PIN', pinPlaceholder: '6-12 位数字', reenter: '再次输入', createWallet: '创建候选钱包', copyAddress: '复制地址', copied: '已复制', protocol: '协议', created: '创建时间', keyStorage: '密钥保管', pinEncrypted: 'PIN 加密', signatureTitle: '所有权签名验证', localVerification: '本地验证', verifySignature: '验证电子签名', verificationResult: '验证结果', valid: '正常', failed: '失败', recoveryCheck: '查看恢复信息', pinRequired: '需要 PIN', openRecovery: '打开恢复信息', recoveryInfo: '恢复信息', hiddenOnClose: '关闭页面后隐藏', recoveryWarning: '任何获得此信息的人都可以控制钱包。请勿保存在聊天、电子邮件或云端笔记中。', mnemonic: '助记词', copyMnemonic: '复制助记词', privateKey: '私钥', copyPrivateKey: '复制私钥', accountOnly: '专用账户', operatorStatus: '运营钱包状态', operatorNotConfigured: '尚未配置运营钱包密钥。', errorLabel: '错误', ownerAccount: '所属账户', candidateBalance: '候选网余额', storageMethod: '保管方式', serverVault: '服务器运营金库', operatorKeyHidden: '运营私钥不会发送到浏览器。', operatorDescription: '此页面仅为 superadmin 账户提供运营钱包的只读权限。外部转账当前为 {state}。', pinMismatch: '两次输入的 PIN 不一致。', walletCreated: 'PLAIS EVM 候选钱包已创建。请安全保管助记词和私钥。', walletExists: 'PLAIS EVM 候选钱包已存在。', recoveryOpened: '恢复信息已显示，关闭页面后将再次隐藏。', signatureValid: '私钥签名验证成功。', signatureFailed: '签名验证失败。', invalidPin: 'PIN 必须为 6-12 位数字。', pinVerificationFailed: 'PIN 验证失败。', walletNotFound: '找不到 PLAIS EVM 钱包。', walletDisabled: 'PLAIS EVM 候选钱包功能已停用。', genericError: '处理钱包时发生错误。'
  },
  ja: {
    title: 'PLAIS EVM 候補ウォレット', adminTitle: 'PLAIS EVM 運用ウォレット', operatorWallet: '運用ウォレット', personalWallet: '個人候補ウォレット', candidateStatus: '候補ネットワーク状態', network: 'ネットワーク', latestBlock: '最新ブロック', externalTransfer: '外部送金', createTitle: '署名ウォレットを作成', createDescription: '標準EVMアドレスと電子署名キーを作成します。現在は候補ネットワーク検証専用で、実資産の入金や外部出金には対応していません。', walletName: 'ウォレット名', securityPin: 'セキュリティPIN', pinConfirm: 'PIN確認', pinPlaceholder: '数字6-12桁', reenter: '再入力', createWallet: '候補ウォレットを作成', copyAddress: 'アドレスをコピー', copied: 'コピー済み', protocol: 'プロトコル', created: '作成日時', keyStorage: 'キー保管', pinEncrypted: 'PIN暗号化', signatureTitle: '所有権署名の検証', localVerification: 'ローカル検証', verifySignature: '電子署名を検証', verificationResult: '検証結果', valid: '正常', failed: '失敗', recoveryCheck: '復旧情報を確認', pinRequired: 'PINが必要', openRecovery: '復旧情報を開く', recoveryInfo: '復旧情報', hiddenOnClose: '画面を閉じると非表示', recoveryWarning: 'この情報を持つ人はウォレットを操作できます。メッセージ、メール、クラウドメモには保存しないでください。', mnemonic: '復旧フレーズ', copyMnemonic: '復旧フレーズをコピー', privateKey: '秘密鍵', copyPrivateKey: '秘密鍵をコピー', accountOnly: '専用アカウント', operatorStatus: '運用ウォレット状態', operatorNotConfigured: '運用ウォレットキーが設定されていません。', errorLabel: 'エラー', ownerAccount: '所有アカウント', candidateBalance: '候補ネット残高', storageMethod: '保管方式', serverVault: 'サーバー運用金庫', operatorKeyHidden: '運用秘密鍵はブラウザに送信されません。', operatorDescription: 'この画面はsuperadminアカウントに運用ウォレットの読み取り専用権限を提供します。外部送金は現在{state}です。', pinMismatch: 'PIN確認が一致しません。', walletCreated: 'PLAIS EVM候補ウォレットを作成しました。復旧フレーズと秘密鍵を安全に保管してください。', walletExists: 'PLAIS EVM候補ウォレットはすでに存在します。', recoveryOpened: '復旧情報を表示しました。この画面を閉じると再び非表示になります。', signatureValid: '秘密鍵の署名検証に成功しました。', signatureFailed: '署名検証に失敗しました。', invalidPin: 'PINは6-12桁の数字で入力してください。', pinVerificationFailed: 'PINの確認に失敗しました。', walletNotFound: 'PLAIS EVMウォレットが見つかりません。', walletDisabled: 'PLAIS EVM候補ウォレットは無効です。', genericError: 'ウォレット処理中にエラーが発生しました。'
  }
};

const TRANSFER_TEXT = {
  ko: {
    balance: '사용 가능 잔액', receive: '받기', receiveDescription: '아래 주소 또는 QR을 보내는 사람에게 전달하세요. PLAIS 후보망 자산만 받을 수 있습니다.', receiveQrAlt: '지갑 받기 QR 코드', send: '보내기', sendDescription: '받는 주소와 금액을 다시 확인한 뒤 전송하세요. 완료된 블록체인 전송은 취소할 수 없습니다.', recipientAddress: '받는 주소', amount: '보낼 수량', estimatedFee: '예상 네트워크 수수료', memo: '메모', optional: '선택 사항', confirmRecipient: '받는 주소와 금액을 확인했습니다.', sendFunds: 'PLAIS 보내기', operatorSend: '운영 지갑에서 보내기', operatorConfirmLabel: '전송 확인 문구', operatorConfirmPlaceholder: 'SEND 입력', transactionHistory: '최근 거래내역', noTransactions: '아직 거래내역이 없습니다.', sent: '보냄', received: '받음', status: '상태', txHash: '거래 해시', block: '블록', fee: '수수료', refresh: '새로고침', sending: '전송 중', sendingDescription: '거래를 제출하고 블록 확정을 기다리고 있습니다. 이 창을 닫지 마세요.', transferCompleteTitle: '전송 완료', transferFailedTitle: '전송 실패', close: '닫기', transferConfirmed: '전송이 블록에 정상 기록되었습니다.', invalidAmount: '보낼 수량이 올바르지 않습니다.', invalidAddress: '받는 지갑 주소가 올바르지 않습니다.', insufficientBalance: '잔액과 네트워크 수수료를 합한 금액이 부족합니다.', transfersLocked: '후보망 전송 기능이 잠겨 있습니다.', signerUnavailable: '지갑 서명 키를 사용할 수 없습니다.', transactionFailed: '블록체인 전송 처리에 실패했습니다.', csrfInvalid: '보안 확인 시간이 만료되었습니다. 페이지를 새로고침한 뒤 다시 시도해 주세요.', confirmationRequired: '전송 확인 항목을 완료해 주세요.', pending: '처리 중', confirmed: '완료', failedStatus: '실패', openExplorer: 'Explorer에서 확인', sendWarning: '주소를 잘못 입력하면 자산을 되돌릴 수 없습니다.', transactionDetail: '거래 상세', from: '보낸 주소', to: '받은 주소', nonce: 'Nonce', gasUsed: '사용 가스', backWallet: '지갑으로 돌아가기', transactionNotFound: '거래를 찾을 수 없습니다.'
  },
  en: {
    balance: 'Available Balance', receive: 'Receive', receiveDescription: 'Share this address or QR code with the sender. Only assets on the PLAIS candidate network can be received.', receiveQrAlt: 'Wallet receive QR code', send: 'Send', sendDescription: 'Verify the recipient and amount before sending. Confirmed blockchain transfers cannot be reversed.', recipientAddress: 'Recipient Address', amount: 'Amount', estimatedFee: 'Estimated Network Fee', memo: 'Memo', optional: 'Optional', confirmRecipient: 'I verified the recipient address and amount.', sendFunds: 'Send PLAIS', operatorSend: 'Send from Operator Wallet', operatorConfirmLabel: 'Transfer Confirmation', operatorConfirmPlaceholder: 'Type SEND', transactionHistory: 'Recent Transactions', noTransactions: 'No transactions yet.', sent: 'Sent', received: 'Received', status: 'Status', txHash: 'Transaction Hash', block: 'Block', fee: 'Fee', refresh: 'Refresh', sending: 'Sending', sendingDescription: 'Submitting the transaction and waiting for block confirmation. Do not close this window.', transferCompleteTitle: 'Transfer Complete', transferFailedTitle: 'Transfer Failed', close: 'Close', transferConfirmed: 'The transfer was confirmed on-chain.', invalidAmount: 'Enter a valid transfer amount.', invalidAddress: 'Enter a valid recipient wallet address.', insufficientBalance: 'The balance is insufficient for the amount and network fee.', transfersLocked: 'Candidate network transfers are locked.', signerUnavailable: 'The wallet signing key is unavailable.', transactionFailed: 'The blockchain transfer failed.', csrfInvalid: 'The security confirmation expired. Refresh the page and try again.', confirmationRequired: 'Complete the transfer confirmation.', pending: 'Pending', confirmed: 'Confirmed', failedStatus: 'Failed', openExplorer: 'View in Explorer', sendWarning: 'Assets cannot be recovered if the address is incorrect.', transactionDetail: 'Transaction Details', from: 'From', to: 'To', nonce: 'Nonce', gasUsed: 'Gas Used', backWallet: 'Back to Wallet', transactionNotFound: 'Transaction not found.'
  },
  zh: {
    balance: '可用余额', receive: '接收', receiveDescription: '请将以下地址或二维码提供给发送方。只能接收 PLAIS 候选网络上的资产。', receiveQrAlt: '钱包收款二维码', send: '发送', sendDescription: '发送前请再次确认接收地址和金额。区块链转账确认后无法撤销。', recipientAddress: '接收地址', amount: '发送数量', estimatedFee: '预计网络手续费', memo: '备注', optional: '可选', confirmRecipient: '我已确认接收地址和金额。', sendFunds: '发送 PLAIS', operatorSend: '从运营钱包发送', operatorConfirmLabel: '转账确认文字', operatorConfirmPlaceholder: '输入 SEND', transactionHistory: '最近交易记录', noTransactions: '暂无交易记录。', sent: '已发送', received: '已接收', status: '状态', txHash: '交易哈希', block: '区块', fee: '手续费', refresh: '刷新', sending: '发送中', sendingDescription: '正在提交交易并等待区块确认，请勿关闭此窗口。', transferCompleteTitle: '转账完成', transferFailedTitle: '转账失败', close: '关闭', transferConfirmed: '转账已成功写入区块。', invalidAmount: '发送数量无效。', invalidAddress: '接收钱包地址无效。', insufficientBalance: '余额不足以支付转账金额和网络手续费。', transfersLocked: '候选网络转账功能已锁定。', signerUnavailable: '无法使用钱包签名密钥。', transactionFailed: '区块链转账失败。', csrfInvalid: '安全验证已过期，请刷新页面后重试。', confirmationRequired: '请完成转账确认。', pending: '处理中', confirmed: '已完成', failedStatus: '失败', openExplorer: '在 Explorer 中查看', sendWarning: '地址错误时资产无法找回。', transactionDetail: '交易详情', from: '发送地址', to: '接收地址', nonce: 'Nonce', gasUsed: '已用 Gas', backWallet: '返回钱包', transactionNotFound: '找不到交易。'
  },
  ja: {
    balance: '利用可能残高', receive: '受け取る', receiveDescription: '以下のアドレスまたはQRコードを送信者に共有してください。PLAIS候補ネットワーク上の資産のみ受け取れます。', receiveQrAlt: 'ウォレット受取QRコード', send: '送る', sendDescription: '送信前に受取アドレスと数量を再確認してください。確定したブロックチェーン送金は取り消せません。', recipientAddress: '受取アドレス', amount: '送信数量', estimatedFee: '予想ネットワーク手数料', memo: 'メモ', optional: '任意', confirmRecipient: '受取アドレスと数量を確認しました。', sendFunds: 'PLAISを送る', operatorSend: '運用ウォレットから送る', operatorConfirmLabel: '送信確認文字', operatorConfirmPlaceholder: 'SENDと入力', transactionHistory: '最近の取引履歴', noTransactions: '取引履歴はまだありません。', sent: '送信', received: '受取', status: '状態', txHash: '取引ハッシュ', block: 'ブロック', fee: '手数料', refresh: '更新', sending: '送信中', sendingDescription: '取引を送信し、ブロック確認を待っています。この画面を閉じないでください。', transferCompleteTitle: '送信完了', transferFailedTitle: '送信失敗', close: '閉じる', transferConfirmed: '送金がブロックに正常に記録されました。', invalidAmount: '正しい送信数量を入力してください。', invalidAddress: '正しい受取ウォレットアドレスを入力してください。', insufficientBalance: '送信額とネットワーク手数料に対して残高が不足しています。', transfersLocked: '候補ネットワークの送金機能はロックされています。', signerUnavailable: 'ウォレット署名キーを使用できません。', transactionFailed: 'ブロックチェーン送金に失敗しました。', csrfInvalid: 'セキュリティ確認の有効期限が切れました。ページを更新して再試行してください。', confirmationRequired: '送信確認を完了してください。', pending: '処理中', confirmed: '完了', failedStatus: '失敗', openExplorer: 'Explorerで確認', sendWarning: 'アドレスを間違えると資産を戻すことはできません。', transactionDetail: '取引詳細', from: '送信元', to: '送信先', nonce: 'Nonce', gasUsed: '使用 Gas', backWallet: 'ウォレットに戻る', transactionNotFound: '取引が見つかりません。'
  }
};

function normalizeLang(value) {
  const raw = String(value || '').trim().toLowerCase();
  if (raw.startsWith('ko')) return 'ko';
  if (raw.startsWith('en')) return 'en';
  if (raw.startsWith('zh')) return 'zh';
  if (raw.startsWith('ja') || raw.startsWith('jp')) return 'ja';
  return '';
}

function parseCookie(req, name) {
  const match = String(req.headers.cookie || '').split(';').map(item => item.trim()).find(item => item.startsWith(`${name}=`));
  return match ? decodeURIComponent(match.slice(name.length + 1)) : '';
}

function resolveLang(req) {
  return normalizeLang(req.query.lang) ||
    normalizeLang(parseCookie(req, 'plais_wallet_lang')) ||
    normalizeLang(req.walletUser && req.walletUser.locale) ||
    normalizeLang(req.headers['accept-language']) ||
    DEFAULT_LANG;
}

function createTranslator(lang) {
  const dictionary = { ...TEXT[lang], ...TRANSFER_TEXT[lang] };
  const fallback = { ...TEXT[DEFAULT_LANG], ...TRANSFER_TEXT[DEFAULT_LANG] };
  return (key, variables = {}) => {
    let value = dictionary[key] || fallback[key] || key;
    for (const [name, replacement] of Object.entries(variables)) {
      value = value.replace(new RegExp(`\\{${name}\\}`, 'g'), String(replacement));
    }
    return value;
  };
}

function buildLangUrl(req, lang) {
  const url = new URL(req.originalUrl || '/wallet/evm', 'https://wallet.local');
  url.searchParams.set('lang', normalizeLang(lang) || DEFAULT_LANG);
  return `${url.pathname}${url.search}`;
}

function localeTag(lang) {
  return { ko: 'ko-KR', en: 'en-US', zh: 'zh-CN', ja: 'ja-JP' }[lang] || 'ko-KR';
}

function errorText(error, t) {
  const keys = {
    INVALID_EVM_PIN: 'invalidPin',
    EVM_WALLET_NOT_FOUND: 'walletNotFound',
    EVM_CANDIDATE_DISABLED: 'walletDisabled',
    INVALID_EVM_AMOUNT: 'invalidAmount',
    INVALID_EVM_ADDRESS: 'invalidAddress',
    INSUFFICIENT_EVM_BALANCE: 'insufficientBalance',
    EVM_TRANSFERS_LOCKED: 'transfersLocked',
    EVM_SIGNER_UNAVAILABLE: 'signerUnavailable',
    EVM_TRANSACTION_FAILED: 'transactionFailed',
    INVALID_WALLET_CSRF: 'csrfInvalid',
    EVM_TRANSFER_CONFIRMATION_REQUIRED: 'confirmationRequired'
    ,INVALID_BSC_ADDRESS: 'invalidAddress'
    ,INVALID_TRON_ADDRESS: 'invalidAddress'
    ,INVALID_BABYDOGE_AMOUNT: 'invalidAmount'
    ,INVALID_BNB_AMOUNT: 'invalidAmount'
    ,INVALID_TRX_AMOUNT: 'invalidAmount'
    ,INSUFFICIENT_BABYDOGE_BALANCE: 'insufficientBalance'
    ,INSUFFICIENT_TRX_BALANCE: 'insufficientBalance'
    ,INSUFFICIENT_BNB_GAS: 'insufficientBalance'
    ,INSUFFICIENT_BNB_BALANCE: 'insufficientBalance'
    ,MULTICHAIN_TRANSFERS_DISABLED: 'transfersLocked'
    ,OPERATOR_SIGNER_OFFLINE: 'transfersLocked'
    ,BSC_CHAIN_ID_MISMATCH: 'transactionFailed'
    ,TRX_BROADCAST_FAILED: 'transactionFailed'
  };
  return t(keys[error && error.code] || 'genericError');
}

module.exports = {
  SUPPORTED_LANGS,
  buildLangUrl,
  createTranslator,
  errorText,
  localeTag,
  normalizeLang,
  resolveLang
};
