import Stripe from 'stripe'
import { Prisma } from '@prisma/client'
import { config, licenseProductName } from '../config.js'
import { prisma } from '../db.js'
import { generateStackLogicLicenseKey } from '../license/generator.js'
import { audit } from '../services/audit.js'
import { sendLicenseEmail } from '../services/email.js'

export const stripe = new Stripe(config.STRIPE_SECRET_KEY)

function stripeId(value: string | { id: string } | null) {
  if (!value) return null
  return typeof value === 'string' ? value : value.id
}

function customerDetails(session: Stripe.Checkout.Session) {
  return {
    email: session.customer_details?.email ?? session.customer_email ?? null,
    fullName: session.customer_details?.name ?? null,
    companyName: session.customer_details?.address?.line2 ?? null,
  }
}

async function hasStackLogicProfessionalLineItem(sessionId: string) {
  const lineItems = await stripe.checkout.sessions.listLineItems(sessionId, {
    limit: 100,
    expand: ['data.price.product'],
  })

  return lineItems.data.some((item) => {
    const price = item.price
    const product = price?.product
    const productId = typeof product === 'string' ? product : product?.id
    return price?.id === config.STACKLOGIC_PRICE_ID && productId === config.STACKLOGIC_PRODUCT_ID
  })
}

export async function fulfillCheckoutSession(session: Stripe.Checkout.Session, stripeEvent: Stripe.Event) {
  if (session.payment_status !== 'paid') {
    return { status: 'ignored', reason: `Payment status is ${session.payment_status}` }
  }

  const isExpectedProduct = await hasStackLogicProfessionalLineItem(session.id)
  if (!isExpectedProduct) {
    return { status: 'ignored', reason: 'Checkout session does not contain the configured StackLogic product/price.' }
  }

  const existingEvent = await prisma.processedStripeEvent.findUnique({
    where: { stripeEventId: stripeEvent.id },
  })
  if (existingEvent) {
    const existingOrder = await prisma.order.findUnique({
      where: { stripeCheckoutSessionId: session.id },
      include: { customer: true, licenses: { orderBy: { createdAt: 'desc' } } },
    })
    const existingLicense = existingOrder?.licenses.find((license) => license.status === 'active') ?? existingOrder?.licenses[0]
    if (existingOrder && existingLicense && existingLicense.emailStatus !== 'sent') {
      await sendLicenseEmail({
        licenseId: existingLicense.id,
        customerEmail: existingOrder.customer.email,
        customerName: existingOrder.customer.fullName,
        licenseKey: existingLicense.licenseKey,
      })
    }
    return { status: 'already_processed', reason: 'Stripe event was already processed.' }
  }

  const details = customerDetails(session)
  const fallbackIssuedTo = details.fullName || details.email || `Stripe ${session.id}`
  const paymentId = stripeId(session.payment_intent)
  const stripeCustomerId = stripeId(session.customer)
  const purchaseDate = new Date((session.created ?? Math.floor(Date.now() / 1000)) * 1000)

  const result = await prisma.$transaction(async (tx) => {
    await tx.processedStripeEvent.create({
      data: {
        stripeEventId: stripeEvent.id,
        eventType: stripeEvent.type,
        objectId: session.id,
        payload: stripeEvent as unknown as Prisma.InputJsonValue,
      },
    })

    const existingOrder = await tx.order.findUnique({
      where: { stripeCheckoutSessionId: session.id },
      include: { customer: true, licenses: { orderBy: { createdAt: 'desc' } } },
    })

    if (existingOrder) {
      return {
        customer: existingOrder.customer,
        order: existingOrder,
        license: existingOrder.licenses.find((license) => license.status === 'active') ?? existingOrder.licenses[0] ?? null,
        created: false,
      }
    }

    const customer = details.email
      ? await tx.customer.upsert({
        where: { email: details.email },
        create: {
          email: details.email,
          fullName: details.fullName,
          companyName: details.companyName,
        },
        update: {
          fullName: details.fullName || undefined,
          companyName: details.companyName || undefined,
        },
      })
      : await tx.customer.create({
        data: {
          fullName: details.fullName,
          companyName: details.companyName,
        },
      })

    const order = await tx.order.create({
      data: {
        customerId: customer.id,
        source: 'stripe',
        stripeCheckoutSessionId: session.id,
        stripePaymentId: paymentId,
        stripeCustomerId,
        product: licenseProductName,
        purchaseAmount: session.amount_total ?? null,
        currency: session.currency ?? null,
        purchaseDate,
        paymentStatus: session.payment_status,
      },
    })

    const { licenseKey } = generateStackLogicLicenseKey({ issuedTo: fallbackIssuedTo })
    const license = await tx.license.create({
      data: {
        customerId: customer.id,
        orderId: order.id,
        licenseKey,
        product: licenseProductName,
        status: 'active',
        source: 'stripe',
        emailStatus: 'pending',
      },
    })

    await tx.auditEvent.createMany({
      data: [
        {
          action: 'stripe_order_recorded',
          customerId: customer.id,
          orderId: order.id,
          metadata: { stripeCheckoutSessionId: session.id, stripePaymentId: paymentId },
        },
        {
          action: 'automatic_license_created_from_stripe',
          customerId: customer.id,
          orderId: order.id,
          licenseId: license.id,
          metadata: { stripeCheckoutSessionId: session.id },
        },
      ],
    })

    return { customer, order, license, created: true }
  })

  if (result.license && result.license.emailStatus !== 'sent') {
    await sendLicenseEmail({
      licenseId: result.license.id,
      customerEmail: result.customer.email,
      customerName: result.customer.fullName,
      licenseKey: result.license.licenseKey,
    })
  } else if (result.license) {
    await audit('stripe_retry_existing_license_email_not_resent', {
      customerId: result.customer.id,
      orderId: result.order.id,
      licenseId: result.license.id,
      metadata: { stripeCheckoutSessionId: session.id },
    })
  }

  return { status: result.created ? 'fulfilled' : 'already_fulfilled', licenseId: result.license?.id }
}
