/**
 * Stripe Webhook Handler
 * Processes payment events and triggers autonomous order-to-cash flow
 */

export const dynamic = 'force-dynamic';

import { NextRequest, NextResponse } from 'next/server';
import { headers } from 'next/headers';
import prisma from '@/lib/db';
import { processPaymentConfirmed, advanceStage } from '@/lib/order-to-cash/orchestrator';
import { logAgentAction } from '@/lib/order-to-cash/agent-logger';

const STRIPE_WEBHOOK_SECRET = process.env.STRIPE_WEBHOOK_SECRET;
const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY;

// Stripe signature verification using Web Crypto API
async function verifyStripeSignature(
  payload: string,
  signature: string,
  secret: string
): Promise<boolean> {
  try {
    const parts = signature.split(',').reduce((acc, part) => {
      const [key, value] = part.split('=');
      acc[key] = value;
      return acc;
    }, {} as Record<string, string>);

    const timestamp = parts['t'];
    const v1Signature = parts['v1'];

    if (!timestamp || !v1Signature) return false;

    // Check timestamp (allow 5 minute tolerance)
    const timestampNum = parseInt(timestamp, 10);
    const now = Math.floor(Date.now() / 1000);
    if (Math.abs(now - timestampNum) > 300) return false;

    // Compute expected signature
    const signedPayload = `${timestamp}.${payload}`;
    const encoder = new TextEncoder();
    const key = await crypto.subtle.importKey(
      'raw',
      encoder.encode(secret),
      { name: 'HMAC', hash: 'SHA-256' },
      false,
      ['sign']
    );
    const signatureBuffer = await crypto.subtle.sign(
      'HMAC',
      key,
      encoder.encode(signedPayload)
    );
    const expectedSignature = Array.from(new Uint8Array(signatureBuffer))
      .map(b => b.toString(16).padStart(2, '0'))
      .join('');

    return expectedSignature === v1Signature;
  } catch (error) {
    console.error('Signature verification error:', error);
    return false;
  }
}

export async function POST(request: NextRequest) {
  try {
    const payload = await request.text();
    const headersList = await headers();
    const signature = headersList.get('stripe-signature');

    // Verify webhook signature if secret is configured
    if (STRIPE_WEBHOOK_SECRET && signature) {
      const isValid = await verifyStripeSignature(payload, signature, STRIPE_WEBHOOK_SECRET);
      if (!isValid) {
        console.error('Invalid Stripe signature');
        return NextResponse.json({ error: 'Invalid signature' }, { status: 400 });
      }
    }

    const event = JSON.parse(payload);
    console.log('Stripe webhook received:', event.type);

    switch (event.type) {
      case 'checkout.session.completed': {
        await handleCheckoutCompleted(event.data.object);
        break;
      }
      case 'payment_intent.succeeded': {
        await handlePaymentSucceeded(event.data.object);
        break;
      }
      case 'payment_intent.payment_failed': {
        await handlePaymentFailed(event.data.object);
        break;
      }
      case 'payout.paid': {
        await handlePayoutPaid(event.data.object);
        break;
      }
      default:
        console.log('Unhandled event type:', event.type);
    }

    return NextResponse.json({ received: true });
  } catch (error) {
    console.error('Webhook error:', error);
    return NextResponse.json(
      { error: 'Webhook handler failed' },
      { status: 500 }
    );
  }
}

async function handleCheckoutCompleted(session: {
  id: string;
  client_reference_id?: string;
  customer?: string;
  payment_intent?: string;
  payment_status: string;
  metadata?: Record<string, string>;
}) {
  const orderId = session.client_reference_id || session.metadata?.order_id;
  if (!orderId) {
    console.error('No order ID in checkout session');
    return;
  }

  const order = await prisma.swagOrder.findUnique({
    where: { id: orderId },
  });

  if (!order) {
    console.error('Order not found:', orderId);
    return;
  }

  // Log the webhook receipt
  await logAgentAction({
    context: {
      executionId: order.workflowExecutionId || orderId,
      orderId,
      orderNumber: order.orderNumber,
      agentName: 'WebhookAgent',
      timestamp: new Date(),
    },
    actionType: 'process_payment',
    targetEntity: 'order',
    targetId: orderId,
    inputData: {
      sessionId: session.id,
      paymentStatus: session.payment_status,
    },
    outputData: { received: true },
  });

  if (session.payment_status === 'paid') {
    // Trigger the autonomous order-to-cash flow
    await processPaymentConfirmed(
      orderId,
      session.payment_intent as string,
      session.customer
    );

    // Clear the cart
    const cart = await prisma.swagCart.findFirst({
      where: {
        items: {
          some: {},
        },
      },
    });
    if (cart) {
      await prisma.swagCartItem.deleteMany({ where: { cartId: cart.id } });
    }
  }
}

async function handlePaymentSucceeded(paymentIntent: {
  id: string;
  metadata?: Record<string, string>;
  customer?: string;
  amount: number;
}) {
  // Find order by payment intent ID
  const order = await prisma.swagOrder.findFirst({
    where: { stripePaymentIntentId: paymentIntent.id },
  });

  if (!order) {
    // May have been handled by checkout.session.completed
    console.log('Order not found for payment intent, may have been processed via checkout session');
    return;
  }

  // Double-check it wasn't already processed
  if (order.paymentStatus === 'paid') {
    console.log('Payment already processed for order:', order.orderNumber);
    return;
  }

  await processPaymentConfirmed(
    order.id,
    paymentIntent.id,
    paymentIntent.customer
  );
}

async function handlePaymentFailed(paymentIntent: {
  id: string;
  metadata?: Record<string, string>;
  last_payment_error?: { message: string };
}) {
  const orderId = paymentIntent.metadata?.order_id;
  if (!orderId) return;

  const order = await prisma.swagOrder.findUnique({ where: { id: orderId } });
  if (!order) return;

  await prisma.swagOrder.update({
    where: { id: orderId },
    data: {
      paymentStatus: 'failed',
      status: 'cancelled',
      notes: paymentIntent.last_payment_error?.message,
    },
  });

  // Update execution status
  if (order.workflowExecutionId) {
    await advanceStage(order.workflowExecutionId, {
      success: false,
      stage: 'payment_processing',
      error: paymentIntent.last_payment_error?.message || 'Payment failed',
    });
  }

  await logAgentAction({
    context: {
      executionId: order.workflowExecutionId || orderId,
      orderId,
      orderNumber: order.orderNumber,
      agentName: 'WebhookAgent',
      timestamp: new Date(),
    },
    actionType: 'process_payment',
    targetEntity: 'order',
    targetId: orderId,
    status: 'failed',
    inputData: { paymentIntentId: paymentIntent.id },
    error: paymentIntent.last_payment_error?.message,
  });
}

async function handlePayoutPaid(payout: {
  id: string;
  amount: number;
  currency: string;
  arrival_date: number;
  destination?: string;
}) {
  // Record payout for reconciliation
  await prisma.stripePayoutRecord.create({
    data: {
      stripePayoutId: payout.id,
      amount: payout.amount / 100, // Convert from cents
      currency: payout.currency.toUpperCase(),
      status: 'paid',
      arrivalDate: new Date(payout.arrival_date * 1000),
      bankAccountLast4: payout.destination?.slice(-4),
    },
  });

  console.log('Payout recorded:', payout.id, payout.amount / 100);
}
