import { NextRequest, NextResponse } from 'next/server';
import { supabaseAdmin, logSignEvent, getSignEvents } from '@/lib/odentas-sign/supabase';
import { uploadEvidenceBundle } from '@/lib/odentas-sign/s3';
import type { EvidenceBundle } from '@/lib/odentas-sign/types';

/**
 * POST /api/odentas-sign/webhooks/completion
 * 
 * Webhook appelé quand tous les signataires ont signé
 * Lance le workflow de scellage : injection signatures → PAdES → TSA → Archive
 */
export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const { requestId } = body;
    
    if (!requestId) {
      return NextResponse.json(
        { error: 'requestId manquant' },
        { status: 400 }
      );
    }
    
    console.log(`[WEBHOOK COMPLETION] Début traitement pour request ${requestId}`);
    
    // 1. Récupérer toutes les données de la demande
    const { data: signRequest, error: requestError } = await supabaseAdmin
      .from('sign_requests')
      .select(`
        *,
        signers(*),
        sign_positions(*)
      `)
      .eq('id', requestId)
      .single();
    
    if (requestError || !signRequest) {
      console.error('[WEBHOOK] Erreur récupération demande:', requestError);
      return NextResponse.json(
        { error: 'Demande introuvable' },
        { status: 404 }
      );
    }
    
    // Vérifier que tous ont bien signé
    const allSigned = signRequest.signers.every((s: any) => s.signed_at !== null);
    if (!allSigned) {
      return NextResponse.json(
        { error: 'Tous les signataires n\'ont pas encore signé' },
        { status: 400 }
      );
    }
    
    // 2. Logger l'événement de début de scellage
    await logSignEvent({
      requestId: signRequest.id,
      event: 'sealing_started',
      metadata: {
        signers_count: signRequest.signers.length,
      },
    });
    
    // 3. Récupérer tous les événements pour le bundle de preuves
    const events = await getSignEvents(requestId);
    
    // 4. Créer le bundle de preuves (evidence)
    const evidenceBundle: EvidenceBundle = {
      request_id: signRequest.id,
      request_ref: signRequest.ref,
      title: signRequest.title,
      created_at: signRequest.created_at,
      completed_at: new Date().toISOString(),
      eidas_level: 'SES', // Signature Électronique Simple pour le moment
      signers: signRequest.signers.map((s: any) => ({
        id: s.id,
        role: s.role,
        name: s.name,
        email: s.email,
        signed_at: s.signed_at,
        ip_address: s.ip_signed || 'N/A',
        user_agent: s.user_agent || 'N/A',
        consent_text: s.consent_text,
        consent_at: s.consent_at,
        signature_method: 'drawn', // TODO: détecter drawn vs uploaded
        authentication: {
          method: 'OTP',
          otp_sent_at: events.find((e: any) => e.event === 'otp_sent' && e.signer_id === s.id)?.ts || 'N/A',
          otp_verified_at: events.find((e: any) => e.event === 'otp_verified' && e.signer_id === s.id)?.ts || 'N/A',
          email_verified: true,
        },
      })),
      events: events.map((e: any) => ({
        timestamp: e.ts,
        event: e.event,
        actor: e.signer_id || null,
        ip: e.ip || null,
        metadata: e.metadata,
      })),
      seal: {
        algorithm: 'RSASSA_PSS_SHA_256',
        kms_key_id: process.env.KMS_KEY_ID || 'N/A',
        sealed_at: '',
        pdf_sha256: '',
      },
      tsa: {
        url: process.env.TSA_URL || 'https://timestamp.sectigo.com',
        tsr_sha256: '',
        policy_oid: null,
        serial: null,
      },
      retention: {
        archive_key: '',
        retain_until: '',
        compliance_mode: 'COMPLIANCE',
      },
    };
    
    // 5. Upload du bundle de preuves initial (sera mis à jour après scellage)
    const evidenceKey = await uploadEvidenceBundle({
      requestRef: signRequest.ref,
      evidence: evidenceBundle,
    });
    
    console.log(`[WEBHOOK] ✅ Evidence bundle uploadé: ${evidenceKey}`);
    
    // 6. Workflow de scellage PAdES + TSA
    console.log(`[WEBHOOK] 🔒 Début du workflow de scellage...`);
    
    try {
      // Étape 1: Appeler lambda-odentas-pades-sign pour sceller le PDF
      console.log(`[WEBHOOK] 📝 Appel de lambda-odentas-pades-sign...`);
      
      const padesPayload = {
        source_s3_key: signRequest.source_s3_key,
        signatures: signRequest.signers.map((s: any) => {
          // Trouver la clé S3 de la signature de ce signataire
          const signatureKey = `signatures/${signRequest.ref}/${s.id}.png`;
          return {
            signer_id: s.id,
            s3_key: signatureKey,
            positions: signRequest.sign_positions
              .filter((p: any) => p.role === s.role)
              .map((p: any) => ({
                page: p.page,
                x: p.x,
                y: p.y,
                width: p.w,
                height: p.h,
              })),
          };
        }),
        output_key: `signed/${signRequest.ref}.pdf`,
      };
      
      console.log(`[WEBHOOK] Payload PAdES:`, JSON.stringify(padesPayload, null, 2));
      
      // Vérifier que les Lambdas sont configurées
      if (!process.env.LAMBDA_PADES_URL || !process.env.LAMBDA_TSA_URL) {
        const error = 'LAMBDA_PADES_URL et LAMBDA_TSA_URL doivent être configurées pour le scellage';
        console.error(`[WEBHOOK] ❌ ${error}`);
        
        // Mettre à jour le statut en 'failed'
        await supabaseAdmin
          .from('sign_requests')
          .update({ status: 'failed' })
          .eq('id', requestId);
        
        await logSignEvent({
          requestId: signRequest.id,
          event: 'sealing_failed',
          metadata: { error, reason: 'Lambda URLs not configured' },
        });
        
        return NextResponse.json(
          { error, details: 'Veuillez configurer LAMBDA_PADES_URL et LAMBDA_TSA_URL dans .env' },
          { status: 500 }
        );
      }
      
      // Appel Lambda PAdES
      const padesResponse = await fetch(process.env.LAMBDA_PADES_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(padesPayload),
      }).catch((err) => {
        console.error('[WEBHOOK] ❌ Erreur appel Lambda PAdES:', err.message);
        throw new Error(`Lambda PAdES inaccessible: ${err.message}`);
      });
      
      if (!padesResponse.ok) {
        const errorText = await padesResponse.text();
        console.error('[WEBHOOK] ❌ Lambda PAdES a échoué:', errorText);
        throw new Error(`Lambda PAdES failed: ${padesResponse.status} - ${errorText}`);
      }
      
      const padesResult = await padesResponse.json();
      console.log(`[WEBHOOK] ✅ PAdES seal appliqué`);
      
      const sealedPdfKey = padesResult.signed_pdf_key;
      const pdfHash = padesResult.pdf_sha256;
      
      // Étape 2: Appeler lambda-tsaStamp pour horodater
      console.log(`[WEBHOOK] ⏱️  Appel de lambda-tsaStamp...`);
      
      const tsaPayload = {
        pdf_s3_key: sealedPdfKey,
        hash_to_timestamp: pdfHash,
      };
      
      const tsaResponse = await fetch(process.env.LAMBDA_TSA_URL, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(tsaPayload),
      }).catch((err) => {
        console.error('[WEBHOOK] ❌ Erreur appel Lambda TSA:', err.message);
        throw new Error(`Lambda TSA inaccessible: ${err.message}`);
      });
      
      if (!tsaResponse.ok) {
        const errorText = await tsaResponse.text();
        console.error('[WEBHOOK] ❌ Lambda TSA a échoué:', errorText);
        throw new Error(`Lambda TSA failed: ${tsaResponse.status} - ${errorText}`);
      }
      
      const tsaResult = await tsaResponse.json();
      console.log(`[WEBHOOK] ✅ TSA timestamp obtenu`);
      
      const tsaSerial = tsaResult.serial_number;
      const tsaPolicyOid = tsaResult.policy_oid;
      const tsrKey = tsaResult.tsr_s3_key;
      
      // Étape 3: Mettre à jour l'evidence bundle avec les infos de scellage
      evidenceBundle.seal.sealed_at = new Date().toISOString();
      evidenceBundle.seal.pdf_sha256 = pdfHash;
      evidenceBundle.tsa.serial = tsaSerial;
      evidenceBundle.tsa.policy_oid = tsaPolicyOid;
      evidenceBundle.tsa.tsr_sha256 = tsrKey;
      evidenceBundle.retention.archive_key = sealedPdfKey;
      
      const retainUntilDate = new Date();
      retainUntilDate.setFullYear(retainUntilDate.getFullYear() + 10);
      evidenceBundle.retention.retain_until = retainUntilDate.toISOString();
      
      // Uploader l'evidence bundle mis à jour
      await uploadEvidenceBundle({
        requestRef: signRequest.ref,
        evidence: evidenceBundle,
      });
      
      console.log(`[WEBHOOK] ✅ Evidence bundle mis à jour`);
      
      // Étape 4: Créer l'enregistrement dans sign_assets
      const { error: assetsError } = await supabaseAdmin
        .from('sign_assets')
        .insert({
          request_id: requestId,
          evidence_json_s3_key: evidenceKey,
          signed_pdf_s3_key: sealedPdfKey,
          tsa_tsr_s3_key: tsrKey || null,
          retain_until: retainUntilDate.toISOString(),
        });
      
      if (assetsError) {
        console.error('[WEBHOOK] Erreur création sign_assets:', assetsError);
      }
      
      // Étape 5: Mettre à jour le statut de la demande
      const { error: updateError } = await supabaseAdmin
        .from('sign_requests')
        .update({ status: 'completed' })
        .eq('id', requestId);
      
      if (updateError) {
        console.error('[WEBHOOK] Erreur mise à jour statut:', updateError);
      }
      
      console.log(`[WEBHOOK] ✅ Workflow de scellage terminé`);
      
    } catch (sealError) {
      console.error('[WEBHOOK] ❌ Erreur workflow de scellage:', sealError);
      
      // Mettre à jour le statut en 'failed' au lieu de 'completed'
      await supabaseAdmin
        .from('sign_requests')
        .update({ status: 'failed' })
        .eq('id', requestId);
      
      await logSignEvent({
        requestId: signRequest.id,
        event: 'sealing_failed',
        metadata: {
          error: sealError instanceof Error ? sealError.message : String(sealError),
        },
      });
      
      return NextResponse.json(
        { 
          error: 'Échec du workflow de scellage', 
          details: sealError instanceof Error ? sealError.message : String(sealError) 
        },
        { status: 500 }
      );
    }
    
    // 7. Logger la completion
    await logSignEvent({
      requestId: signRequest.id,
      event: 'request_completed',
      metadata: {
        evidence_key: evidenceKey,
        status: 'completed',
      },
    });
    
    // 8. TODO: Envoyer les emails de notification aux signataires
    console.log(`[WEBHOOK] TODO: Envoyer emails de completion`);
    
    console.log(`[WEBHOOK COMPLETION] ✅ Traitement terminé pour ${signRequest.ref}`);
    
    return NextResponse.json({
      success: true,
      message: 'Workflow de scellage terminé',
      request: {
        id: signRequest.id,
        ref: signRequest.ref,
        status: 'completed',
      },
      evidence_key: evidenceKey,
    });
    
  } catch (error) {
    console.error('[WEBHOOK COMPLETION] Erreur:', error);
    return NextResponse.json(
      { error: 'Erreur serveur', details: error instanceof Error ? error.message : String(error) },
      { status: 500 }
    );
  }
}
