// middlewares/checkTokenMiddleware.ts
import { Request, Response, NextFunction } from "express";
import { Subscription } from "../models/Subscription";
import { User } from "../models/User";
import jwt from "jsonwebtoken";

export const checkTokenMiddleware = async (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  try {
    console.log("[Middleware] checkToken triggered on:", req.path);

    // 🔹 Read token from cookies
    const token = req.cookies?.token;

    // 🔹 Handle guest users (no token)
    if (!token) {
      console.log("[Middleware] Guest user detected, bypassing token check");
      // No token validation or subscription check for guests
      // Pass down minimal info if needed (e.g., guest status)
      (req as any).user = { id: null, role: "guest" };
      return next();
    }

    // 🔹 Verify JWT for logged-in users
    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;
    }

    // 🔹 Find user
    const user = await User.query().findById(decoded.id);
    if (!user) {
      res.status(401).json({ message: "Unauthorized: User not found" });
      return;
    }

    // 🔹 Find active subscription
    const subscription = await Subscription.query()
      .where("user_id", user.id)
      .first();

    if (!subscription) {
      res.status(403).json({ message: "No active subscription found." });
      return;
    }

    // 🔹 Check expiry date
    if (
      subscription.expiry_date &&
      new Date(subscription.expiry_date) < new Date()
    ) {
      res
        .status(403)
        .json({ message: "Your package has expired. Please renew." });
      return;
    }

    // 🔹 Validate input text
    const text: string = req.body?.inputText;
    if (!text || typeof text !== "string" || text.trim().length === 0) {
      res.status(400).json({ message: "Invalid request: No input text" });
      return;
    }

    // 🔹 Calculate usage
    const charCount = text.length;
    const tokenCount = Math.ceil(charCount / 4); // 1 token = 4 chars

    // 🔹 Prevent negative or zero quotas
    if (
      Number(subscription.left_words) <= 0 ||
      Number(subscription.left_token) <= 0
    ) {
      res.status(403).json({
        message: "Your subscription has no quota left. Please upgrade.",
      });
      return;
    }

    // 🔹 Atomic DB update (avoids race conditions)
    const updated = await Subscription.query()
      .where("id", subscription.id)
      .where("left_words", ">=", charCount)
      .where("left_token", ">=", tokenCount)
      .patch({
        left_words: subscription.left_words - charCount,
        used_words: subscription.used_words + charCount,
        left_token: subscription.left_token - tokenCount,
        used_token: subscription.used_token + tokenCount,
        updated_at: new Date().toISOString(),
      });

    if (!updated) {
      res.status(403).json({
        message: "Quota exceeded or race condition detected. Please try again.",
      });
      return;
    }

    console.log(
      `[Middleware] Deducted ${charCount} chars / ${tokenCount} tokens for user ${user.id}`
    );

    // 🔹 Optionally log usage (for audit purposes)
    // await UsageLog.query().insert({
    //   user_id: user.id,
    //   subscription_id: subscription.id,
    //   chars_used: charCount,
    //   tokens_used: tokenCount,
    //   route: req.path,
    //   created_at: new Date().toISOString(),
    // });

    // Pass down user + subscription info if needed
    (req as any).user = user;
    (req as any).subscription = subscription;

    next();
  } catch (error) {
    console.error("[Middleware Error]", error);
    res.status(500).json({ message: "Internal server error" });
    return;
  }
};
