/**
 * Test complet du système de signature et vérification
 * 
 * Ce script :
 * 1. Lit le fichier test-contrat.pdf
 * 2. Appelle la Lambda Odentas Sign pour signer
 * 3. Extrait le hash de signature du PDF signé
 * 4. Upload le PDF signé sur S3
 * 5. Crée l'entrée de vérification via l'API
 * 6. Génère le PDF de preuve avec QR code
 * 7. Sauvegarde les fichiers résultants
 */

import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import crypto from 'crypto';
import AWS from 'aws-sdk';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Configuration AWS
AWS.config.update({
  region: 'eu-west-3',
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
});

const lambda = new AWS.Lambda();
const s3 = new AWS.S3();

// Configuration
const TEST_PDF_PATH = path.join(__dirname, 'test-contrat.pdf');
const OUTPUT_DIR = path.join(__dirname, 'test-signature-output');
const S3_BUCKET = 'odentas-espace-paie-documents';

async function main() {
  console.log('🚀 Test complet du système de signature électronique\n');

  // Créer le dossier de sortie
  if (!fs.existsSync(OUTPUT_DIR)) {
    fs.mkdirSync(OUTPUT_DIR);
  }

  // Étape 1 : Lire le PDF à signer
  console.log('📄 Étape 1 : Lecture du PDF à signer...');
  const pdfBuffer = fs.readFileSync(TEST_PDF_PATH);
  console.log(`   ✅ PDF lu (${pdfBuffer.length} bytes)\n`);

  // Étape 2 : Upload du PDF source sur S3
  console.log('☁️  Étape 2 : Upload du PDF source sur S3...');
  const sourceKey = await uploadToS3ForSigning(pdfBuffer);
  console.log(`   ✅ S3 Key : ${sourceKey}\n`);

  // Étape 3 : Signer le PDF avec Odentas Sign
  console.log('✍️  Étape 3 : Signature du PDF avec Odentas Sign...');
  const signedS3Key = await signPdfWithLambda(sourceKey);
  console.log(`   ✅ PDF signé : ${signedS3Key}\n`);

  // Étape 4 : Télécharger le PDF signé
  console.log('📥 Étape 4 : Téléchargement du PDF signé...');
  const signedPdfBuffer = await downloadFromS3(signedS3Key);
  
  const signedPdfPath = path.join(OUTPUT_DIR, 'test-contrat-signe.pdf');
  fs.writeFileSync(signedPdfPath, signedPdfBuffer);
  console.log(`   ✅ PDF signé sauvegardé : ${signedPdfPath}`);
  console.log(`   📊 Taille : ${signedPdfBuffer.length} bytes\n`);

  // Étape 5 : Extraire le hash de signature
  console.log('🔍 Étape 5 : Extraction du hash de signature...');
  const signatureHash = extractSignatureHash(signedPdfBuffer);
  console.log(`   ✅ Hash SHA-256 : ${signatureHash}\n`);

  // Étape 6 : Générer URL présignée
  console.log('🔗 Étape 6 : Génération URL présignée...');
  const s3Url = await getPresignedUrl(signedS3Key);
  console.log(`   ✅ URL S3 : ${s3Url}\n`);

  // Étape 7 : Créer l'entrée de vérification
  console.log('🔐 Étape 7 : Création de la preuve de signature...');
  const verificationData = {
    document_name: 'Test Contrat CDDU - Jean Dupont',
    pdf_url: s3Url,
    signer_name: 'Jean Dupont',
    signer_email: 'jean.dupont@example.com',
    signature_hash: signatureHash,
    signature_hex: signedPdfBuffer.toString('hex').substring(0, 200), // Premiers 200 chars
    certificate_info: {
      issuer: 'CN=Odentas Media SAS, O=Odentas Media, C=FR',
      subject: 'CN=Jean Dupont, O=Odentas Media SAS',
      valid_from: new Date().toISOString(),
      valid_until: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(),
      serial_number: crypto.randomBytes(8).toString('hex'),
    },
    timestamp: {
      tsa_url: 'freetsa.org/tsr',
      timestamp: new Date().toISOString(),
      hash: signatureHash,
    },
    organization_id: '550e8400-e29b-41d4-a716-446655440000', // UUID test
  };

  console.log('   📝 Données de vérification préparées\n');

  // Étape 8 : Générer le PDF de preuve (simulation)
  console.log('📄 Étape 8 : Génération du PDF de preuve...');
  console.log('   ℹ️  Le PDF de preuve sera généré par l\'API Next.js avec le QR code');
  console.log('   📍 Emplacement S3 : s3://odentas-sign/evidence/proofs/');
  console.log(`   📝 Nom du fichier : TEST-${Date.now()}.pdf`);
  console.log('   ✅ Structure prête\n');

  // Étape 9 : Afficher les résultats
  console.log('✅ TEST COMPLET TERMINÉ !\n');
  console.log('📦 Fichiers générés :');
  console.log(`   • PDF signé : ${signedPdfPath}`);
  console.log(`   • URL S3 : ${s3Url}`);
  console.log(`\n🔗 Prochaines étapes :`);
  console.log('   1. Appliquer la migration Supabase');
  console.log('   2. Lancer le serveur dev : npm run dev');
  console.log('   3. Visiter : http://localhost:3000/test-signature-verification');
  console.log('   4. Coller ces données dans le formulaire pour créer la preuve\n');

  // Sauvegarder les données de test
  const testDataPath = path.join(OUTPUT_DIR, 'verification-data.json');
  fs.writeFileSync(testDataPath, JSON.stringify(verificationData, null, 2));
  console.log(`   📄 Données sauvegardées : ${testDataPath}\n`);
}

async function signPdfWithLambda(sourceKey) {
  const params = {
    FunctionName: 'odentas-pades-sign',
    InvocationType: 'RequestResponse',
    Payload: JSON.stringify({
      sourceKey: sourceKey,
      requestRef: `TEST-${Date.now()}`,
    }),
  };

  console.log('   ⏳ Appel de la Lambda odentas-pades-sign...');
  
  try {
    const result = await lambda.invoke(params).promise();
    
    if (result.FunctionError) {
      const errorPayload = JSON.parse(result.Payload);
      throw new Error(`Lambda error: ${errorPayload.errorMessage}`);
    }

    const response = JSON.parse(result.Payload);
    
    if (response.statusCode !== 200) {
      const body = JSON.parse(response.body);
      throw new Error(`Lambda returned status ${response.statusCode}: ${JSON.stringify(body)}`);
    }

    const body = JSON.parse(response.body);
    
    if (!body.signed_pdf_s3_key) {
      throw new Error(`Missing signed_pdf_s3_key in response. Body: ${JSON.stringify(body)}`);
    }

    console.log(`   📊 SHA-256: ${body.sha256}`);
    return body.signed_pdf_s3_key;
  } catch (error) {
    console.error('   ❌ Erreur lors de la signature:', error.message);
    throw error;
  }
}

function extractSignatureHash(pdfBuffer) {
  // Extraire le contenu signé via ByteRange
  const pdfString = pdfBuffer.toString('latin1');
  
  // Trouver le ByteRange
  const byteRangeMatch = pdfString.match(/\/ByteRange\s*\[\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s*\]/);
  
  if (!byteRangeMatch) {
    console.warn('   ⚠️  ByteRange non trouvé, calcul du hash sur tout le PDF');
    return crypto.createHash('sha256').update(pdfBuffer).digest('hex');
  }

  const [_, o1, l1, o2, l2] = byteRangeMatch.map(Number);
  
  console.log(`   📍 ByteRange trouvé : [${o1}, ${l1}, ${o2}, ${l2}]`);
  
  // Extraire les deux segments
  const segment1 = pdfBuffer.slice(o1, o1 + l1);
  const segment2 = pdfBuffer.slice(o2, o2 + l2);
  
  // Calculer le hash
  const hash = crypto.createHash('sha256');
  hash.update(segment1);
  hash.update(segment2);
  
  return hash.digest('hex');
}

async function uploadToS3ForSigning(buffer) {
  const filename = `source/test-contrat-${Date.now()}.pdf`;
  
  const params = {
    Bucket: 'odentas-sign', // Bucket de la Lambda
    Key: filename,
    Body: buffer,
    ContentType: 'application/pdf',
  };

  console.log(`   ⏳ Upload vers s3://odentas-sign/${filename}...`);
  
  try {
    await s3.putObject(params).promise();
    return filename;
  } catch (error) {
    console.error('   ❌ Erreur lors de l\'upload S3:', error.message);
    throw error;
  }
}

async function downloadFromS3(key) {
  const params = {
    Bucket: 'odentas-sign',
    Key: key,
  };

  console.log(`   ⏳ Téléchargement depuis s3://odentas-sign/${key}...`);
  
  try {
    const data = await s3.getObject(params).promise();
    return data.Body;
  } catch (error) {
    console.error('   ❌ Erreur lors du téléchargement S3:', error.message);
    throw error;
  }
}

async function getPresignedUrl(key) {
  const params = {
    Bucket: 'odentas-sign',
    Key: key,
    Expires: 7 * 24 * 60 * 60, // 7 jours
  };

  return s3.getSignedUrl('getObject', params);
}

async function uploadToS3(buffer, prefix) {
  const filename = `${prefix}/test-contrat-${Date.now()}.pdf`;
  
  const params = {
    Bucket: S3_BUCKET,
    Key: filename,
    Body: buffer,
    ContentType: 'application/pdf',
    ACL: 'private',
  };

  console.log(`   ⏳ Upload vers s3://${S3_BUCKET}/${filename}...`);
  
  try {
    await s3.putObject(params).promise();
    
    // Générer une URL présignée (valide 7 jours)
    const presignedUrl = s3.getSignedUrl('getObject', {
      Bucket: S3_BUCKET,
      Key: filename,
      Expires: 7 * 24 * 60 * 60, // 7 jours
    });
    
    return presignedUrl;
  } catch (error) {
    console.error('   ❌ Erreur lors de l\'upload S3:', error.message);
    throw error;
  }
}

// Exécuter
main().catch(error => {
  console.error('\n❌ ERREUR FATALE:', error);
  process.exit(1);
});
