import { S3Client, GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
import { KMSClient, SignCommand } from '@aws-sdk/client-kms';
import fs from 'node:fs/promises';
import { PDFDocument } from 'pdf-lib';
import * as createPAdES 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 || ''; // ARN ou KeyId
const TSA_LAMBDA_NAME = process.env.TSA_LAMBDA_NAME || 'odentas-tsa-stamp';

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');

    // 1) Télécharger PDF source
    const get = await s3.send(new GetObjectCommand({ Bucket: BUCKET, Key: sourceKey }));
    const inputPdf = await streamToBuffer(get.Body);

    // 2) Télécharger chain.pem (signer.crt [+ intermediate]) depuis S3
    const chainObj = await s3.send(new GetObjectCommand({ Bucket: BUCKET, Key: CHAIN_S3_KEY }));
    const chainData = await streamToBuffer(chainObj.Body); // Buffer (PEM texte ou DER)

    // 3) Construire le PDF avec placeholder signature et obtenir le "toSign" (byteRange bytes)
    const { pdfWithPlaceholder, byteRangeInfo, pdfStructure, incrementalUpdate } = await createPAdES.preparePdfWithPlaceholder(inputPdf, requestRef);

    // 4) Calculer digest des SignedAttributes (signature-ready digest) via helper
    const { signedAttributesDer, signedAttributesDigest, tempPdfWithRevision, contentsStart, contentsEnd } = await createPAdES.buildSignedAttributesDigest(pdfWithPlaceholder, byteRangeInfo, pdfStructure, incrementalUpdate);

    // 5) Demander à KMS de signer le digest (MessageType = DIGEST)
    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(signedAttributesDigest),
      MessageType: 'DIGEST',
      SigningAlgorithm: 'RSASSA_PSS_SHA_256'
    }));
    const signatureBytes = Buffer.from(signResp.Signature);
    console.log('[KMS] Signature length:', signatureBytes.length, 'bytes');

    // 6) Construire la structure PKCS#7 SignedData (pkijs helper) en injectant signatureBytes et chainPem
    const cmsDer = await createPAdES.buildCmsSignedData(signedAttributesDer, signatureBytes, chainData);

    // 7) (optionnel) demander et intégrer le token TSA (PAdES-T) — TODO pour v2

    // 8) Injecter le CMS dans le PDF (Contents) et finaliser
    const finalPdf = await createPAdES.finalizePdfWithCms(pdfWithPlaceholder, byteRangeInfo, pdfStructure, incrementalUpdate, cmsDer, tempPdfWithRevision, contentsStart, contentsEnd);

    // Hash utile pour vérification et traçabilité
    const finalSha256 = crypto.createHash('sha256').update(finalPdf).digest('hex');
    console.info('[pades] final PDF bytes =', finalPdf.length, ' sha256=', finalSha256);

    // 9) Upload PDF final (avec métadonnées)
    const signedKey = `${SIGNED_PREFIX}${requestRef}.pdf`;
    await s3.send(new PutObjectCommand({
      Bucket: BUCKET,
      Key: signedKey,
      Body: finalPdf,
      ContentType: 'application/pdf',
      Metadata: {
        requestRef,
        pades: 'BES-proto',
        sha256: finalSha256,
      }
    }));

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

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