const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const crypto = require('crypto');

const app = express();
const PORT = 3001;

app.use(helmet());
app.use(cors());
app.use(express.json());

// Almacenamiento en memoria para pruebas
const transactions = new Map();
const movements = new Map();

// Configuración de APIs mock
const MOCK_CONFIG = {
  '0102': { // BDV
    api_key: '96R7T1T5J2134T5YFC2GF15SDFG4BD1Z',
    webhook_key: '97F6F54EF1A84F3A24FE19A3B338C77A'
  },
  '0156': { // 100% Banco
    api_key: '256D0FDD36F1B1B3F1208A9B6EC693',
    api_secret: 'tu_api_secret_100banco',
    merchant_id: '885847',
    terminal_id: 'us3lc2p'
  }
};

// ==================== BANCO DE VENEZUELA MOCK ====================

// Endpoint de conciliación BDV
app.post('/getMovement/v2', (req, res) => {
  const apiKey = req.headers['x-api-key'];
  
  if (apiKey !== MOCK_CONFIG['0102'].api_key) {
    return res.status(403).json({
      code: 1001,
      message: "API Key inválida",
      status: 403
    });
  }

  const {
    cedulaPagador,
    telefonoPagador,
    telefonoDestino,
    referencia,
    fechaPago,
    importe,
    bancoOrigen,
    reqCed
  } = req.body;

  // Validaciones básicas
  if (!cedulaPagador || !telefonoPagador || !referencia || !importe) {
    return res.status(400).json({
      code: 1002,
      message: "Datos incompletos",
      status: 400
    });
  }

  // Simular diferentes escenarios basados en la referencia
  let response;
  if (referencia.includes('ERROR')) {
    response = {
      code: 1001,
      message: "Transacción no encontrada",
      data: {
        status: "1001",
        amount: importe,
        reason: "Transacción no existe"
      },
      status: 404
    };
  } else if (referencia.includes('DUPLICADO')) {
    response = {
      code: 1003,
      message: "Transacción duplicada",
      data: {
        status: "1003",
        amount: importe,
        reason: "Ya existe una transacción con esta referencia"
      },
      status: 409
    };
  } else {
    // Transacción exitosa
    response = {
      code: 1000,
      message: `Monto: ${importe} - estatus : Transaccion realizada`,
      data: {
        status: "1000",
        amount: importe,
        reason: "Transaccion realizada"
      },
      status: 200
    };

    // Guardar transacción para consultas posteriores
    transactions.set(referencia, {
      ...req.body,
      status: 'completed',
      timestamp: new Date()
    });
  }

  res.json(response);
});

// Endpoint de consulta de movimientos BDV
app.post('/apis/bdv/consulta/movimientos/v2', (req, res) => {
  const apiKey = req.headers['x-api-key'];
  
  if (apiKey !== MOCK_CONFIG['0102'].api_key) {
    return res.status(403).json({
      code: "1001",
      message: "API Key inválida",
      status: 403
    });
  }

  const { cuenta, fechaIni, fechaFin, tipoMoneda, nroMovimiento } = req.body;

  // Generar movimientos mock
  const mockMovements = [
    {
      referencia: "0205329143958",
      descripcion: "COMISION PUNTOYA",
      fecha: "2024-01-15",
      hora: "1032",
      mov: "DEBITO",
      saldo: "217.947.805,89",
      importe: "-0.13",
      nroMov: "4923",
      observacion: "CANAL 40 TRASPASO CON CUENTA N 0102050183000328337"
    },
    {
      referencia: "0303329143958",
      descripcion: "OPERACION PUNTOYA BDV",
      fecha: "2024-01-15",
      hora: "1032",
      mov: "CREDITO",
      saldo: "217.947.806,02",
      importe: "150.75",
      nroMov: "4922",
      observacion: "PAGOMOVIL BDV V27037606"
    },
    {
      referencia: "0205327931140",
      descripcion: "COMISION PUNTOYA",
      fecha: "2024-01-15",
      hora: "1012",
      mov: "DEBITO",
      saldo: "217.947.805,02",
      importe: "-0.13",
      nroMov: "4921",
      observacion: "CANAL 40 TRASPASO CON CUENTA N 0102050183000328337"
    },
    {
      referencia: "0303327931140",
      descripcion: "OPERACION PUNTOYA BDV",
      fecha: "2024-01-15",
      hora: "1012",
      mov: "CREDITO",
      saldo: "217.947.805,15",
      importe: "200.50",
      nroMov: "4920",
      observacion: "PAGOMOVIL BDV V25346789"
    }
  ];

  res.json({
    code: "1000",
    message: "",
    data: {
      totalOfMovements: mockMovements.length,
      movs: mockMovements
    },
    status: 200
  });
});

// ==================== 100% BANCO MOCK ====================

// Función para generar firma (igual que el banco real)
function generateSignature100(apiSecret, endpoint, date, body) {
  const host = 'www8.100x100banco.com';
  const bodyHash = crypto.createHash('sha256').update(JSON.stringify(body)).digest('hex');
  const bodyHashBase64 = Buffer.from(bodyHash, 'hex').toString('base64');
  const signatureString = host + endpoint + date + bodyHashBase64;
  
  const hmac = crypto.createHmac('sha256', apiSecret);
  hmac.update(signatureString);
  const signatureHex = hmac.digest('hex');
  return Buffer.from(signatureHex, 'hex').toString('base64');
}

// Validar transacción 100% Banco
app.post('/100p2pCert/api/v1/ValTrxIn', (req, res) => {
  const apiKey = req.headers['x-api-key'];
  const dateHeader = req.headers['date'];
  const signatureHeader = req.headers['x-signature'];
  
  // Validar API Key
  if (apiKey !== MOCK_CONFIG['0156'].api_key) {
    return res.json({
      sMerchantId: req.body.sMerchantId,
      sTrxType: req.body.sTrxType,
      sTrxId: req.body.sTrxId,
      sReferenceNo: "",
      sRespCode: "801",
      sRespDesc: "Comercio no registrado API",
      sTerminalId: req.body.sTerminalId,
      sReqId: ""
    });
  }

  // Validar firma
  const expectedSignature = generateSignature100(
    MOCK_CONFIG['0156'].api_secret,
    '/100p2pCert/api/v1/ValTrxIn',
    dateHeader,
    req.body
  );

  if (signatureHeader !== expectedSignature) {
    return res.json({
      sMerchantId: req.body.sMerchantId,
      sTrxType: req.body.sTrxType,
      sTrxId: req.body.sTrxId,
      sReferenceNo: "",
      sRespCode: "55",
      sRespDesc: "TOKEN inválido",
      sTerminalId: req.body.sTerminalId,
      sReqId: ""
    });
  }

  const {
    sMerchantId,
    sTrxId,
    sTrxType,
    sBankId,
    sDocumentId,
    sFromAcctNo,
    sToAcctNo,
    nAmount,
    sReferenceNo,
    sDateTrx,
    sTerminalId
  } = req.body;

  // Validaciones de negocio
  let responseCode = "00";
  let responseDesc = "Transaccion Aprobada";

  // Simular diferentes casos de error basados en los datos
  if (sFromAcctNo.includes('9999')) {
    responseCode = "14";
    responseDesc = "Número móvil receptor errado o no afiliado";
  } else if (nAmount > 1000) {
    responseCode = "23";
    responseDesc = "Monto de la transacción no permitido";
  } else if (sFromAcctNo.includes('0000')) {
    responseCode = "39";
    responseDesc = "Saldo Insuficiente";
  } else if (sDocumentId.includes('INVALIDO')) {
    responseCode = "80";
    responseDesc = "Documento de identificación errado";
  } else if (sTrxId && transactions.has(sTrxId)) {
    responseCode = "24";
    responseDesc = "Operación duplicada";
  }

  // Generar referencia bancaria mock
  const bankReference = responseCode === "00" 
    ? `45${Math.random().toString().substring(2, 8)}`
    : "";

  // Generar ReqId mock
  const reqId = responseCode === "00"
    ? Buffer.from(`mock_req_id_${Date.now()}_${sTrxId}`).toString('base64')
    : "";

  // Guardar transacción
  if (responseCode === "00") {
    transactions.set(sTrxId, {
      ...req.body,
      status: 'completed',
      bankReference,
      timestamp: new Date()
    });
  }

  res.json({
    sMerchantId,
    sTrxType,
    sTrxId,
    sReferenceNo: bankReference,
    sRespCode: responseCode,
    sRespDesc: responseDesc,
    sTerminalId,
    sReqId: reqId
  });
});

// ==================== WEBHOOK SIMULATOR ====================

// Simulador de webhook BDV
app.post('/simulate-webhook/bdv', (req, res) => {
  const {
    referencia,
    bancoOrdenante = "0102",
    idCliente = "V27037606",
    numeroCliente = "04127141363",
    idComercio = "J503045019",
    numeroComercio = "04127141363",
    monto = "150.75"
  } = req.body;

  if (!referencia) {
    return res.status(400).json({ error: "Se requiere referencia" });
  }

  // Crear payload de webhook BDV
  const now = new Date();
  const fecha = now.toISOString().slice(0, 10).replace(/-/g, '');
  const hora = now.toTimeString().slice(0, 4).replace(':', '');

  const webhookPayload = {
    bancoOrdenante,
    referenciaBancoOrdenante: referencia,
    idCliente,
    numeroCliente,
    idComercio,
    numeroComercio,
    fecha,
    hora,
    monto
  };

  // Enviar webhook a nuestra API principal (debes cambiar la URL según tu configuración)
  const targetUrl = 'http://localhost:3000/api/v1/webhooks/0102/notification';
  
  fetch(targetUrl, {
    method: 'POST',
    headers: {
      'API-KEY': MOCK_CONFIG['0102'].webhook_key,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(webhookPayload)
  })
  .then(response => response.json())
  .then(data => {
    res.json({
      message: "Webhook simulado enviado",
      payload: webhookPayload,
      response: data
    });
  })
  .catch(error => {
    res.status(500).json({
      error: "Error enviando webhook",
      details: error.message
    });
  });
});

// ==================== ENDPOINTS DE ADMIN ====================

// Ver todas las transacciones registradas
app.get('/admin/transactions', (req, res) => {
  const transactionsArray = Array.from(transactions.entries()).map(([key, value]) => ({
    reference: key,
    ...value
  }));
  
  res.json({
    total: transactionsArray.length,
    transactions: transactionsArray
  });
});

// Limpiar transacciones (para testing)
app.delete('/admin/transactions', (req, res) => {
  const previousSize = transactions.size;
  transactions.clear();
  res.json({
    message: `Transacciones limpiadas (${previousSize} eliminadas)`
  });
});

// Health check
app.get('/health', (req, res) => {
  res.json({
    status: 'OK',
    service: 'Mock Bank API',
    timestamp: new Date().toISOString(),
    endpoints: {
      bdv: {
        conciliation: '/getMovement/v2',
        movements: '/apis/bdv/consulta/movimientos/v2'
      },
      banco100: {
        validation: '/100p2pCert/api/v1/ValTrxIn'
      },
      webhooks: {
        simulator: '/simulate-webhook/bdv'
      },
      admin: {
        transactions: '/admin/transactions'
      }
    }
  });
});

app.listen(PORT, () => {
  console.log(`🏦 Mock Bank API ejecutándose en puerto ${PORT}`);
  console.log(`📍 Health check: http://localhost:${PORT}/health`);
  console.log(`📍 Banco de Venezuela Mock: http://localhost:${PORT}/getMovement/v2`);
  console.log(`📍 100% Banco Mock: http://localhost:${PORT}/100p2pCert/api/v1/ValTrxIn`);
  console.log(`📍 Webhook Simulator: http://localhost:${PORT}/simulate-webhook/bdv`);
});

module.exports = app;