import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
import { KMSClient, SignCommand } from '@aws-sdk/client-kms';
import * as pades from './helpers/pades.js';
import crypto from 'node:crypto';

const region = process.env.REGION || 'eu-west-3';
const s3 = new S3Client({ region });
const kms = new KMSClient({ region });

const BUCKET = process.env.BUCKET || 'odentas-sign';
const SIGNED_PREFIX = process.env.SIGNED_PREFIX || 'signed-pades/';
const CHAIN_S3_KEY = process.env.SIGNER_CHAIN_S3_KEY || 'certs/chain.pem';
const KMS_KEY_ID = process.env.KMS_KEY_ID || '';

export const handler = async (event) => {
  try {
    const requestRef = event.requestRef || `REQ-${Date.now()}`;
    const sourceKey = event.sourceKey || event.pdfS3Key;
    if (!sourceKey) throw new Error('sourceKey manquant');

    console.log('[START] requestRef:', requestRef, 'sourceKey:', sourceKey);

    // 1. Télécharger PDF source
    const getPdf = await s3.send(new GetObjectCommand({ Bucket: BUCKET, Key: sourceKey }));
    const inputPdf = await streamToBuffer(getPdf.Body);
    console.log('[PDF] Downloaded, size:', inputPdf.length, 'bytes');

    // 2. Télécharger chain.pem
    const getChain = await s3.send(new GetObjectCommand({ Bucket: BUCKET, Key: CHAIN_S3_KEY }));
    const chainPem = await streamToBuffer(getChain.Body);
    console.log('[CHAIN] Downloaded, size:', chainPem.length, 'bytes');

    // 3. Préparer le PDF avec les vraies valeurs ByteRange (calculées en 2 passes)
    const {
      pdfWithRevision,
      byteRange,
      contentsPlaceholder,
      signingTime
    } = await pades.preparePdfWithPlaceholder(inputPdf);
    console.log('[PREPARE] PDF with revision ready, size:', pdfWithRevision.length, 'bytes');
    console.log('[PREPARE] Signing time:', signingTime);
    console.log('[PREPARE] ByteRange:', byteRange);

    // 4. Calculer le digest des SignedAttributes (ByteRange déjà correct dans le PDF)
    const {
      signedAttrs,
      signedAttrsDigest,
      pdfDigest
    } = pades.buildSignedAttributesDigest(pdfWithRevision, byteRange, signingTime, chainPem.toString('utf-8'));

    // 5. Signer avec KMS
    if (!KMS_KEY_ID) throw new Error('KMS_KEY_ID non défini');
    const signResp = await kms.send(new SignCommand({
      KeyId: KMS_KEY_ID,
      Message: Buffer.from(signedAttrsDigest),
      MessageType: 'DIGEST',
      SigningAlgorithm: 'RSASSA_PSS_SHA_256'
    }));
    const signatureBytes = Buffer.from(signResp.Signature);
    console.log('[KMS] Signature length:', signatureBytes.length, 'bytes');

    // 6. Construire le CMS SignedData
    const cmsDer = await pades.buildCmsSignedData(signedAttrs, signatureBytes, chainPem);
    const cmsHex = cmsDer.toString('hex');
    console.log('[CMS] Built, hex length:', cmsHex.length);

    // 7. Finaliser le PDF avec la signature (remplacer UNIQUEMENT /Contents)
    const finalPdf = pades.finalizePdfWithCms(
      pdfWithRevision,
      byteRange,
      cmsHex
    );
    
    const finalSha256 = crypto.createHash('sha256').update(finalPdf).digest('hex');
    console.log('[FINAL] PDF size:', finalPdf.length, 'bytes, SHA256:', finalSha256);

    // 8. Upload vers S3
    const signedKey = `${SIGNED_PREFIX}${requestRef}.pdf`;
    await s3.send(new PutObjectCommand({
      Bucket: BUCKET,
      Key: signedKey,
      Body: finalPdf,
      ContentType: 'application/pdf',
      Metadata: {
        requestRef,
        pades: 'BES',
        sha256: finalSha256,
      }
    }));

    console.log('[SUCCESS] Signed PDF uploaded to:', signedKey);

    return {
      statusCode: 200,
      body: JSON.stringify({
        status: 'signed',
        requestRef,
        signed_pdf_s3_key: signedKey,
        sha256: finalSha256
      })
    };
  } catch (err) {
    console.error('[ERROR]', err);
    return {
      statusCode: 500,
      body: JSON.stringify({ error: String(err), stack: err.stack })
    };
  }
};

async function streamToBuffer(stream) {
  const chunks = [];
  for await (const chunk of stream) chunks.push(chunk);
  return Buffer.concat(chunks);
}
