import { NextRequest, NextResponse } from 'next/server'
import { prisma } from '@/lib/prisma'
import { stripeService } from '@/lib/services/stripe-service'
import {
  OrderStatus,
  AutomationMode,
  SubscriptionStatus,
  UserStatus,
} from '@prisma/client'
import { emailService } from '@/lib/services/email-service'
import { randomBytes } from 'crypto'
import bcrypt from 'bcryptjs'

/**
 * Generate a customer ID slug from company/user name
 * Only lowercase letters allowed (env_setup.sh requires ^[a-z]+$)
 */
function slugifyCustomer(name: string): string {
  return name
    .toLowerCase()
    .replace(/[^a-z]/g, '')
    .substring(0, 32)
}

/**
 * Generate a unique license key for the order
 */
function generateLicenseKey(): string {
  const hex = randomBytes(16).toString('hex')
  return `lb_inst_${hex}`
}

/**
 * POST /api/v1/webhooks/stripe
 *
 * Handles Stripe webhook events. The primary event is checkout.session.completed,
 * which creates a Customer, Order, and Subscription in the Hub database.
 *
 * Important: The raw body must be passed to constructEvent for signature verification.
 * Next.js App Router provides the raw body via request.text().
 */
export async function POST(request: NextRequest) {
  if (!stripeService.isConfigured()) {
    console.error('Stripe webhook received but Stripe is not configured')
    return NextResponse.json(
      { error: 'Stripe is not configured' },
      { status: 500 }
    )
  }

  // Get the raw body as text for signature verification
  const rawBody = await request.text()

  // Get the Stripe signature header
  const signature = request.headers.get('stripe-signature')
  if (!signature) {
    return NextResponse.json(
      { error: 'Missing stripe-signature header' },
      { status: 400 }
    )
  }

  // Verify webhook signature and construct event
  let event
  try {
    event = stripeService.constructWebhookEvent(rawBody, signature)
  } catch (err) {
    const message = err instanceof Error ? err.message : 'Unknown error'
    console.error(`Stripe webhook signature verification failed: ${message}`)
    return NextResponse.json(
      { error: `Webhook signature verification failed: ${message}` },
      { status: 400 }
    )
  }

  // Handle the event
  try {
    switch (event.type) {
      case 'checkout.session.completed': {
        await handleCheckoutSessionCompleted(event.data.object as unknown as Record<string, unknown>)
        break
      }

      default:
        // Acknowledge other events without processing
        console.log(`Unhandled Stripe event type: ${event.type}`)
    }
  } catch (err) {
    const message = err instanceof Error ? err.message : 'Unknown error'
    console.error(`Error handling Stripe event ${event.type}: ${message}`)
    return NextResponse.json(
      { error: `Failed to handle event: ${message}` },
      { status: 500 }
    )
  }

  return NextResponse.json({ received: true })
}

/**
 * Handle checkout.session.completed event
 *
 * 1. Find or create User by email
 * 2. Create Subscription with Stripe IDs
 * 3. Create Order with PAYMENT_CONFIRMED status
 */
async function handleCheckoutSessionCompleted(
  session: Record<string, unknown>
) {
  const customerEmail = session.customer_email as string | undefined
  const customerName = (session.metadata as Record<string, string>)?.customer_name
  const customerDomain = (session.metadata as Record<string, string>)?.domain
  const stripeCustomerId = session.customer as string | undefined
  const stripeSubscriptionId = session.subscription as string | undefined

  if (!customerEmail) {
    throw new Error('checkout.session.completed missing customer_email')
  }

  // Extract plan info from session metadata
  const planMapping = stripeService.extractPlanFromSession(
    session as unknown as import('stripe').Stripe.Checkout.Session
  )
  if (!planMapping) {
    throw new Error(
      'Could not determine plan from checkout session. ' +
      'Ensure metadata includes price_id or plan.'
    )
  }

  // 1. Find or create User
  let user = await prisma.user.findUnique({
    where: { email: customerEmail },
  })

  if (!user) {
    const randomPassword = randomBytes(16).toString('hex')
    const passwordHash = await bcrypt.hash(randomPassword, 10)

    user = await prisma.user.create({
      data: {
        email: customerEmail,
        name: customerName || null,
        passwordHash,
        status: UserStatus.ACTIVE,
      },
    })
  }

  // 2. Create Subscription
  await prisma.subscription.create({
    data: {
      userId: user.id,
      plan: planMapping.plan,
      tier: planMapping.tier,
      tokenLimit: planMapping.tokenLimit,
      status: SubscriptionStatus.ACTIVE,
      stripeCustomerId: stripeCustomerId || null,
      stripeSubscriptionId: stripeSubscriptionId || null,
    },
  })

  // 3. Create Order
  const displayName = customerName || user.company || user.name || 'customer'
  const customerSlug = slugifyCustomer(displayName) || 'customer'
  const domain = customerDomain || `${customerSlug}.letsbe.cloud`
  const licenseKey = generateLicenseKey()

  await prisma.order.create({
    data: {
      userId: user.id,
      domain,
      tier: planMapping.tier,
      tools: planMapping.tools,
      status: OrderStatus.PAYMENT_CONFIRMED,
      automationMode: AutomationMode.AUTO,
      source: 'stripe',
      customer: customerSlug,
      companyName: displayName,
      licenseKey,
      configJson: {
        tools: planMapping.tools,
        tier: planMapping.tier,
        domain,
        stripeSessionId: session.id as string,
        stripeCustomerId,
        stripeSubscriptionId,
      },
    },
  })

  console.log(
    `Stripe checkout completed: created order for ${customerEmail} ` +
    `(plan: ${planMapping.plan}, domain: ${domain})`
  )

  // 4. Send welcome email (non-blocking - don't fail webhook on email error)
  try {
    const emailResult = await emailService.sendWelcomeEmail({
      to: customerEmail,
      customerName: customerName || user.name || '',
      plan: planMapping.plan,
      domain,
    })
    if (!emailResult.success) {
      console.warn(`Welcome email failed for ${customerEmail}: ${emailResult.error}`)
    }
  } catch (emailErr) {
    console.warn('Failed to send welcome email:', emailErr)
  }
}
