import { Router } from 'express'
import { z } from 'zod'
import { prisma } from '../lib/prisma'
import { requireCompanyAuth } from '../middleware/requireCompanyAuth'
import { requireTenant } from '../middleware/requireTenant'
import { requireSubscription } from '../middleware/requireSubscription'
import * as amanpay from '../services/amanpayService'
import * as paypal from '../services/paypalService'

const router = Router()

// ─── Webhook endpoints (no auth — must come before middleware) ──────────────

router.post('/webhooks/amanpay', async (req, res, next) => {
  try {
    const rawBody = JSON.stringify(req.body)
    const signature = req.headers['x-amanpay-signature'] as string ?? ''

    if (amanpay.isConfigured() && !amanpay.verifyWebhookSignature(rawBody, signature)) {
      return res.status(401).json({ error: 'invalid_signature' })
    }

    const event = req.body
    const transactionId = event.transaction_id ?? event.id
    const orderId = event.order_id ?? event.metadata?.order_id
    const status = event.status?.toUpperCase()

    if (status === 'PAID' || status === 'SUCCEEDED') {
      const payment = await prisma.rentalPayment.findFirst({ where: { amanpayTransactionId: transactionId } })
      if (payment) {
        await prisma.rentalPayment.update({
          where: { id: payment.id },
          data: { status: 'SUCCEEDED', paidAt: new Date() },
        })
        await prisma.reservation.update({
          where: { id: payment.reservationId },
          data: { paymentStatus: 'PAID', paidAmount: { increment: payment.amount } },
        })
      }
    } else if (status === 'FAILED') {
      await prisma.rentalPayment.updateMany({
        where: { amanpayTransactionId: transactionId },
        data: { status: 'FAILED' },
      })
    }

    res.json({ received: true })
  } catch (err) { next(err) }
})

router.post('/webhooks/paypal', async (req, res, next) => {
  try {
    const rawBody = JSON.stringify(req.body)
    const isValid = await paypal.verifyWebhookEvent(
      req.headers as Record<string, string>,
      rawBody,
    )
    if (paypal.isConfigured() && !isValid) {
      return res.status(401).json({ error: 'invalid_signature' })
    }

    const event = req.body
    const eventType = event.event_type as string

    if (eventType === 'PAYMENT.CAPTURE.COMPLETED') {
      const captureId = event.resource?.id as string
      const payment = await prisma.rentalPayment.findFirst({ where: { paypalCaptureId: captureId } })
      if (payment) {
        await prisma.rentalPayment.update({
          where: { id: payment.id },
          data: { status: 'SUCCEEDED', paidAt: new Date() },
        })
        await prisma.reservation.update({
          where: { id: payment.reservationId },
          data: { paymentStatus: 'PAID', paidAmount: { increment: payment.amount } },
        })
      }
    } else if (eventType === 'PAYMENT.CAPTURE.DENIED') {
      const captureId = event.resource?.id as string
      await prisma.rentalPayment.updateMany({
        where: { paypalCaptureId: captureId },
        data: { status: 'FAILED' },
      })
    }

    res.json({ received: true })
  } catch (err) { next(err) }
})

// ─── Authenticated routes ────────────────────────────────────────────────────

router.use(requireCompanyAuth, requireTenant, requireSubscription)

const chargeSchema = z.object({
  provider: z.enum(['AMANPAY', 'PAYPAL']),
  type: z.enum(['CHARGE', 'DEPOSIT']).default('CHARGE'),
  currency: z.enum(['MAD', 'USD', 'EUR']).default('MAD'),
  successUrl: z.string().url(),
  failureUrl: z.string().url(),
})

router.get('/reservations/:id', async (req, res, next) => {
  try {
    const payments = await prisma.rentalPayment.findMany({
      where: { reservationId: req.params.id, companyId: req.companyId },
      orderBy: { createdAt: 'desc' },
    })
    res.json({ data: payments })
  } catch (err) { next(err) }
})

router.post('/reservations/:id/charge', async (req, res, next) => {
  try {
    const { provider, type, currency, successUrl, failureUrl } = chargeSchema.parse(req.body)

    const reservation = await prisma.reservation.findFirstOrThrow({
      where: { id: req.params.id, companyId: req.companyId },
      include: { vehicle: true, customer: true },
    })

    if (reservation.paymentStatus === 'PAID') {
      return res.status(409).json({ error: 'already_paid', message: 'Reservation is already fully paid', statusCode: 409 })
    }

    const amount = type === 'DEPOSIT' ? reservation.depositAmount : reservation.totalAmount
    const description = `${type === 'DEPOSIT' ? 'Deposit' : 'Rental'}: ${reservation.vehicle.make} ${reservation.vehicle.model}`
    const orderId = `${reservation.id}-${type}-${Date.now()}`
    const webhookBase = process.env.API_URL ?? 'http://localhost:4000'

    let checkoutUrl: string
    let amanpayTransactionId: string | null = null
    let paypalCaptureId: string | null = null

    if (provider === 'AMANPAY') {
      if (!amanpay.isConfigured()) {
        return res.status(503).json({ error: 'provider_not_configured', message: 'AmanPay is not configured', statusCode: 503 })
      }
      const result = await amanpay.createCheckout({
        amount,
        currency,
        orderId,
        description,
        customerEmail: reservation.customer.email,
        customerName: `${reservation.customer.firstName} ${reservation.customer.lastName}`,
        successUrl,
        failureUrl,
        webhookUrl: `${webhookBase}/api/v1/payments/webhooks/amanpay`,
      })
      checkoutUrl = result.checkoutUrl
      amanpayTransactionId = result.transactionId
    } else {
      if (!paypal.isConfigured()) {
        return res.status(503).json({ error: 'provider_not_configured', message: 'PayPal is not configured', statusCode: 503 })
      }
      const result = await paypal.createOrder({
        amount,
        currency,
        orderId,
        description,
        returnUrl: successUrl,
        cancelUrl: failureUrl,
      })
      checkoutUrl = result.approveUrl
      paypalCaptureId = result.orderId
    }

    const payment = await prisma.rentalPayment.create({
      data: {
        companyId: req.companyId,
        reservationId: reservation.id,
        amount,
        currency,
        status: 'PENDING',
        type,
        paymentProvider: provider,
        amanpayTransactionId,
        paypalCaptureId,
      },
    })

    res.json({ data: { payment, checkoutUrl } })
  } catch (err) { next(err) }
})

router.post('/reservations/:id/capture-paypal', async (req, res, next) => {
  try {
    const { paypalOrderId } = z.object({ paypalOrderId: z.string() }).parse(req.body)

    const payment = await prisma.rentalPayment.findFirstOrThrow({
      where: { paypalCaptureId: paypalOrderId, companyId: req.companyId },
    })

    const capture = await paypal.captureOrder(paypalOrderId) as Record<string, any>
    const captureId = capture.purchase_units?.[0]?.payments?.captures?.[0]?.id ?? paypalOrderId

    const updated = await prisma.rentalPayment.update({
      where: { id: payment.id },
      data: { status: 'SUCCEEDED', paidAt: new Date(), paypalCaptureId: captureId },
    })

    await prisma.reservation.update({
      where: { id: payment.reservationId },
      data: { paymentStatus: 'PAID', paidAmount: { increment: payment.amount } },
    })

    res.json({ data: updated })
  } catch (err) { next(err) }
})

router.post('/reservations/:reservationId/payments/:paymentId/refund', async (req, res, next) => {
  try {
    const { amount, reason } = z.object({
      amount: z.number().int().positive().optional(),
      reason: z.string().optional(),
    }).parse(req.body)

    const payment = await prisma.rentalPayment.findFirstOrThrow({
      where: { id: req.params.paymentId, companyId: req.companyId, reservationId: req.params.reservationId },
    })

    if (payment.status !== 'SUCCEEDED') {
      return res.status(400).json({ error: 'not_capturable', message: 'Only succeeded payments can be refunded', statusCode: 400 })
    }

    const refundAmount = amount ?? payment.amount

    if (payment.paymentProvider === 'AMANPAY') {
      if (!payment.amanpayTransactionId) throw new Error('No AmanPay transaction ID')
      await amanpay.refundTransaction(payment.amanpayTransactionId, refundAmount, reason)
    } else {
      if (!payment.paypalCaptureId) throw new Error('No PayPal capture ID')
      await paypal.refundCapture(payment.paypalCaptureId, refundAmount, payment.currency, reason)
    }

    const isPartial = refundAmount < payment.amount
    const updated = await prisma.rentalPayment.update({
      where: { id: payment.id },
      data: { status: isPartial ? 'PARTIALLY_REFUNDED' : 'REFUNDED' },
    })

    if (!isPartial) {
      await prisma.reservation.update({
        where: { id: payment.reservationId },
        data: { paymentStatus: 'REFUNDED' },
      })
    }

    res.json({ data: updated })
  } catch (err) { next(err) }
})

export default router
