import { Request, Response, NextFunction, RequestHandler } from "express";
import Stripe from "stripe";
import jwt from "jsonwebtoken";
import { PricingPlan } from "../models/PricingPlan";
import { Subscription } from "../models/Subscription";
import { User } from "../models/User";
import { UserTransaction } from "../models/UserTransaction";
import dotenv from "dotenv";

dotenv.config(); // load .env variables
console.log("STRIPE_SECRET_KEY:", process.env.STRIPE_SECRET_KEY);

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY as string, {
  apiVersion: "2025-08-27.basil",
});

export class StripeController {
  // ✅ Create Checkout Session
  payment: RequestHandler = async (req, res, next) => {
    const token = req.cookies?.token;
    if (!token) {
      res.status(401).json({ message: "Unauthorized: No token provided" });
      return;
    }

    let decoded: any;
    try {
      decoded = jwt.verify(token, process.env.JWT_SECRET_FRONTEND as string);
    } catch (err) {
      res
        .status(401)
        .json({ message: "Unauthorized: Invalid or expired token" });
      return;
    }

    const userId = decoded?.id;
    const { planId } = req.body;

    if (!userId || !planId) {
      res.status(400).json({ message: "User ID and Plan ID are required" });
      return;
    }

    try {
      const plan = await PricingPlan.query().findById(planId);
      if (!plan) {
        res.status(404).json({ message: "Plan not found" });
        return;
      }

      const session = await stripe.checkout.sessions.create({
        payment_method_types: ["card"],
        mode: "payment",
        customer_email: decoded.email,
        line_items: [
          {
            price_data: {
              currency: "usd",
              product_data: { name: plan.plan_name },
              unit_amount: Math.round(Number(plan.price) * 100), // ensure integer
            },
            quantity: 1,
          },
        ],
        success_url: `${process.env.FRONTEND_DOMAIN}/payment/success?session_id={CHECKOUT_SESSION_ID}`,
        cancel_url: `${process.env.FRONTEND_DOMAIN}/pricing`,
        metadata: { userId, planId },
      });

      res.json({ id: session.id, url: session.url });
    } catch (err) {
      console.error("Stripe error:", err);
      res.status(500).json({ message: "Payment session creation failed" });
    }
  };

  // ✅ Stripe Webhook Handler
  webhook: RequestHandler = async (req, res) => {
    console.log("STRIPE WEB HOOK", process.env.STRIPE_WEBHOOK_SECRET);
    const sig = req.headers["stripe-signature"] as string;

    let event: Stripe.Event;
    try {
      console.log("Webhook Trigger");

      event = stripe.webhooks.constructEvent(
        req.body, // this must be raw Buffer from express.raw()
        sig,
        process.env.STRIPE_WEBHOOK_SECRET as string
      );
    } catch (err: any) {
      console.error("❌ Webhook signature verification failed:", err.message);
      res.status(400).send(`Webhook Error: ${err.message}`);
      return;
    }

    if (event.type === "checkout.session.completed") {
      const session = event.data.object as Stripe.Checkout.Session;
      const userId = session.metadata?.userId;
      const planId = session.metadata?.planId;

      if (userId && planId) {
        const plan = await PricingPlan.query()
          .findById(planId)
          .withGraphFetched("query");

        if (plan) {
          // 1️⃣ Save Stripe customer ID in user table
          if (session.customer && typeof session.customer === "string") {
            await User.query().patchAndFetchById(userId, {
              stripe_id: session.customer,
            });
          }

          // 2️⃣ Calculate expiry date
          let expiryDate = new Date();
          switch (plan.duration) {
            case "weekly":
              expiryDate = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
              break;
            case "monthly":
              expiryDate.setMonth(expiryDate.getMonth() + 1);
              break;
            case "quarterly":
              expiryDate.setMonth(expiryDate.getMonth() + 3);
              break;
            case "yearly":
              expiryDate.setFullYear(expiryDate.getFullYear() + 1);
              break;
          }

          // 3️⃣ Insert Subscription
          await Subscription.query().insert({
            user_id: userId,
            plan_id: plan.id,
            queries_id: plan.query.id,
            used_token: 0,
            left_token: plan.query.total_token,
            used_words: 0,
            left_words: plan.query.total_characters,
            expiry_date: expiryDate,
          });

          // 4️⃣ Log Transaction
          await UserTransaction.query().insert({
            user_id: userId,
            stripe_id: session.payment_intent as string,
            pay_amount: plan.price - (Number(plan.discount) || 0),
            transaction: event.type,
          });

          console.log(
            `✅ Subscription + Transaction logged for user ${userId}`
          );
        }
      }
    }

    res.json({ received: true });
  };
  verify: RequestHandler = async (req, res, next) => {
    try {
      const sessionId = req.query.session_id as string;
      if (!sessionId) {
        res.status(400).json({ success: false, message: "Missing session_id" });
        return;
      }

      // Fetch checkout session from Stripe
      const session = await stripe.checkout.sessions.retrieve(sessionId);

      if (session.payment_status === "paid") {
        res.json({ success: true, session });
        return;
      } else {
        res.json({
          success: false,
          message: "Payment not completed yet",
        });
        return;
      }
    } catch (err) {
      console.error(err);
      res.status(500).json({ success: false, message: "Server error" });
      return;
    }
  };
}
