import { Router, Request, Response } from 'express';
import Stripe from 'stripe';
import { PrismaClient } from '@prisma/client';
import { authenticate, AuthRequest } from '../middleware/auth';
import { z } from 'zod';

const router = Router();
const prisma = new PrismaClient();
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

const SUBSCRIPTION_PRICES: Record<string, string> = {
  basic: process.env.STRIPE_PRICE_BASIC!,    // $9.99/mo
  pro: process.env.STRIPE_PRICE_PRO!,        // $19.99/mo
  lifetime: process.env.STRIPE_PRICE_LIFETIME! // $149 one-time
};

// POST /api/payments/checkout - purchase a plan
router.post('/checkout', authenticate, async (req: AuthRequest, res: Response) => {
  try {
    const { planId, couponCode } = z.object({
      planId: z.string(),
      couponCode: z.string().optional()
    }).parse(req.body);

    const plan = await prisma.ketoPlan.findUnique({ where: { id: planId } });
    if (!plan) return res.status(404).json({ error: 'Plan not found' });
    if (!plan.published) return res.status(404).json({ error: 'Plan not available' });

    // Check if already purchased
    const existing = await prisma.purchase.findUnique({
      where: { userId_planId: { userId: req.user!.id, planId } }
    });
    if (existing) return res.status(409).json({ error: 'Already purchased' });

    let discountAmount = 0;
    let stripeCouponId: string | undefined;

    // Validate coupon
    if (couponCode) {
      const coupon = await prisma.coupon.findFirst({
        where: {
          code: couponCode.toUpperCase(),
          active: true,
          validFrom: { lte: new Date() },
          OR: [{ validUntil: null }, { validUntil: { gte: new Date() } }],
          OR: [{ maxUses: null }, { maxUses: { gt: prisma.coupon.fields.usedCount } }]
        }
      });

      if (!coupon) return res.status(400).json({ error: 'Invalid or expired coupon' });

      discountAmount = coupon.discountType === 'PERCENTAGE'
        ? plan.price * (coupon.discountValue / 100)
        : coupon.discountValue;
    }

    // Get or create Stripe customer
    let user = await prisma.user.findUnique({ where: { id: req.user!.id } });
    let customerId = user?.stripeCustomerId;

    if (!customerId) {
      const customer = await stripe.customers.create({
        email: user!.email,
        name: user!.name || undefined
      });
      customerId = customer.id;
      await prisma.user.update({
        where: { id: req.user!.id },
        data: { stripeCustomerId: customerId }
      });
    }

    const finalAmount = Math.max(0, plan.price - discountAmount);

    const session = await stripe.checkout.sessions.create({
      customer: customerId,
      payment_method_types: ['card'],
      line_items: [{
        price_data: {
          currency: 'usd',
          product_data: { name: plan.title, description: plan.shortDesc },
          unit_amount: Math.round(finalAmount * 100)
        },
        quantity: 1
      }],
      mode: 'payment',
      success_url: `${process.env.FRONTEND_URL}/dashboard?purchase=success&planId=${planId}`,
      cancel_url: `${process.env.FRONTEND_URL}/plans/${plan.slug}?purchase=cancelled`,
      metadata: {
        userId: req.user!.id,
        planId,
        couponCode: couponCode || ''
      },
      discounts: stripeCouponId ? [{ coupon: stripeCouponId }] : undefined
    });

    res.json({ checkoutUrl: session.url, sessionId: session.id });
  } catch (err: any) {
    if (err instanceof z.ZodError) return res.status(400).json({ error: 'Validation error', details: err.errors });
    console.error('Checkout error:', err);
    res.status(500).json({ error: 'Failed to create checkout session' });
  }
});

// POST /api/payments/subscribe - start subscription
router.post('/subscribe', authenticate, async (req: AuthRequest, res: Response) => {
  try {
    const { tier } = z.object({ tier: z.enum(['basic', 'pro', 'lifetime']) }).parse(req.body);
    const priceId = SUBSCRIPTION_PRICES[tier];
    if (!priceId) return res.status(400).json({ error: 'Invalid tier' });

    let user = await prisma.user.findUnique({ where: { id: req.user!.id } });
    let customerId = user?.stripeCustomerId;

    if (!customerId) {
      const customer = await stripe.customers.create({ email: user!.email, name: user!.name || undefined });
      customerId = customer.id;
      await prisma.user.update({ where: { id: req.user!.id }, data: { stripeCustomerId: customerId } });
    }

    const isLifetime = tier === 'lifetime';

    const session = await stripe.checkout.sessions.create({
      customer: customerId,
      payment_method_types: ['card'],
      line_items: [{ price: priceId, quantity: 1 }],
      mode: isLifetime ? 'payment' : 'subscription',
      success_url: `${process.env.FRONTEND_URL}/dashboard?subscription=success`,
      cancel_url: `${process.env.FRONTEND_URL}/pricing?cancelled=true`,
      metadata: { userId: req.user!.id, tier }
    });

    res.json({ checkoutUrl: session.url });
  } catch (err: any) {
    if (err instanceof z.ZodError) return res.status(400).json({ error: 'Validation error', details: err.errors });
    res.status(500).json({ error: 'Failed to create subscription session' });
  }
});

// POST /api/payments/portal - customer billing portal
router.post('/portal', authenticate, async (req: AuthRequest, res: Response) => {
  try {
    const user = await prisma.user.findUnique({ where: { id: req.user!.id } });
    if (!user?.stripeCustomerId) return res.status(400).json({ error: 'No billing account found' });

    const session = await stripe.billingPortal.sessions.create({
      customer: user.stripeCustomerId,
      return_url: `${process.env.FRONTEND_URL}/dashboard`
    });

    res.json({ url: session.url });
  } catch {
    res.status(500).json({ error: 'Failed to open billing portal' });
  }
});

// POST /api/payments/webhook - Stripe webhook
router.post('/webhook', async (req: Request, res: Response) => {
  const sig = req.headers['stripe-signature']!;
  let event: Stripe.Event;

  try {
    event = stripe.webhooks.constructEvent(req.body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
  } catch {
    return res.status(400).json({ error: 'Invalid webhook signature' });
  }

  try {
    switch (event.type) {
      case 'checkout.session.completed': {
        const session = event.data.object as Stripe.CheckoutSession;
        const { userId, planId, couponCode, tier } = session.metadata || {};

        if (planId) {
          // Single plan purchase
          const order = await prisma.order.create({
            data: {
              userId,
              stripePaymentId: session.payment_intent as string,
              amount: (session.amount_total || 0) / 100,
              status: 'COMPLETED'
            }
          });

          await prisma.purchase.create({
            data: { userId, planId, orderId: order.id, price: (session.amount_total || 0) / 100 }
          });

          await prisma.ketoPlan.update({
            where: { id: planId },
            data: { purchaseCount: { increment: 1 } }
          });

          if (couponCode) {
            await prisma.coupon.update({
              where: { code: couponCode },
              data: { usedCount: { increment: 1 } }
            });
          }
        }

        if (tier) {
          // Lifetime purchase
          if (tier === 'lifetime') {
            await prisma.user.update({
              where: { id: userId },
              data: {
                role: 'PREMIUM',
                subscriptionTier: 'LIFETIME',
                subscriptionStatus: 'ACTIVE'
              }
            });
          }
        }
        break;
      }

      case 'customer.subscription.created':
      case 'customer.subscription.updated': {
        const sub = event.data.object as Stripe.Subscription;
        const user = await prisma.user.findFirst({
          where: { stripeCustomerId: sub.customer as string }
        });
        if (!user) break;

        const priceId = sub.items.data[0]?.price.id;
        let tier: 'BASIC' | 'PRO' = 'BASIC';
        if (priceId === SUBSCRIPTION_PRICES.pro) tier = 'PRO';

        const status = sub.status === 'active' ? 'ACTIVE'
          : sub.status === 'canceled' ? 'CANCELED'
          : sub.status === 'past_due' ? 'PAST_DUE'
          : 'INACTIVE';

        await prisma.user.update({
          where: { id: user.id },
          data: {
            role: status === 'ACTIVE' ? 'PREMIUM' : 'MEMBER',
            subscriptionTier: tier,
            subscriptionStatus: status,
            subscriptionEndsAt: new Date(sub.current_period_end * 1000)
          }
        });

        await prisma.subscription.upsert({
          where: { userId: user.id },
          create: {
            userId: user.id,
            stripeSubscriptionId: sub.id,
            tier,
            status,
            currentPeriodStart: new Date(sub.current_period_start * 1000),
            currentPeriodEnd: new Date(sub.current_period_end * 1000)
          },
          update: {
            status,
            currentPeriodStart: new Date(sub.current_period_start * 1000),
            currentPeriodEnd: new Date(sub.current_period_end * 1000)
          }
        });
        break;
      }

      case 'customer.subscription.deleted': {
        const sub = event.data.object as Stripe.Subscription;
        const user = await prisma.user.findFirst({ where: { stripeCustomerId: sub.customer as string } });
        if (!user) break;

        await prisma.user.update({
          where: { id: user.id },
          data: { role: 'MEMBER', subscriptionTier: 'FREE', subscriptionStatus: 'CANCELED' }
        });
        break;
      }
    }

    res.json({ received: true });
  } catch (err) {
    console.error('Webhook processing error:', err);
    res.status(500).json({ error: 'Webhook processing failed' });
  }
});

export { router as paymentRouter };
