const { Op } = require("sequelize");
const { Companies, Users, Projects, Subscriptions } = require("../models");
const Stripe = require("stripe");

const getSubscriptionDetails = async (req, res) => {
  const permissions = ["admin", "super-admin"];
  if (!permissions.includes(req.user?.role))
    return res.status(403).json({ message: "Forbidden" });

  try {
    const company = await Companies.findByPk(req.user.companyId);
    if (!company)
      return res.status(404).json({ message: "Something went wrong" });
    const subscription = await Subscriptions.findOne({
      where: {
        CompanyId: req.user.companyId,
      },
      order: [["createdAt", "DESC"]],
    });
    if (!subscription)
      return res.status(404).json({ message: "Something went wrong" });
    const usersCount = await Users.count({
      where: {
        CompanyId: req.user.companyId,
        role: {
          [Op.or]: ["user", "admin", "super-admin"],
        },
      },
    });
    const projectsCount = await Projects.count({
      where: {
        CompanyId: req.user.companyId,
      },
    });

    return res.json({
      status:
        subscription.subscriptionEndsAt < Date.now()
          ? "expired"
          : subscription.subscriptionType == "free trial"
            ? "trial"
            : "active",
      subscriptionEndsAt: subscription.subscriptionEndsAt,
      companyEmail: company.email,
      usage: {
        users: {
          used: usersCount,
          limit: subscription.usersCount,
          perItemPrice: subscription.userPrice,
        },
        projects: {
          used: projectsCount,
          limit: subscription.projectsCount,
          perItemPrice: subscription.projectPrice,
        },
        sdsSearch: {
          used: subscription.monthlySDSSearchUsage,
          limit: subscription.monthlySDSSearchCount,
          perItemPrice: subscription.SDSSearchPerSavePrice,
        },
        sdsSave: {
          used: subscription.monthlySDSSaveUsage,
          limit: subscription.monthlySDSSaveCount,
          perItemPrice: subscription.SDSSavePrice,
        },
      },
    });
  } catch (error) {
    return res.status(500).json({ message: "Failed to fetch" });
  }
};

const webhook = async (req, res) => {
  const sig = req.headers["stripe-signature"];

  let event;
  const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
  try {
    event = stripe.webhooks.constructEvent(
      req.body,
      sig,
      process.env.STRIPE_WEBHOOK_SECRET,
    );
  } catch (err) {
    res.status(400).send(`Webhook Error: ${err.message}`);
    return;
  }

  if (event.type !== "checkout.session.completed")
    return res.status(400).send(`The event type is not supported`);

  const session = await stripe.checkout.sessions.retrieve(
    event.data.object.id,
    {
      expand: ["line_items"],
    },
  );

  if (!session) return res.status(400).send(`No session found`);

  const companyId = session.metadata.companyId;

  if (!companyId) return res.status(400).send(`No email found`);

  const company = await Companies.findByPk(companyId);

  if (!company) return res.status(400).send(`No company found`);

  const subscription = await Subscriptions.findOne({
    where: {
      CompanyId: company.id,
    },
    order: [["createdAt", "DESC"]],
  });

  if (!subscription)
    return res.status(404).json({ message: "Subscription not found" });

  const newSubscriptionEndsAt = new Date();
  newSubscriptionEndsAt.setMonth(newSubscriptionEndsAt.getMonth() + 1);

  await Subscriptions.update(
    {
      subscriptionEndsAt: newSubscriptionEndsAt,
      subscriptionType: "paid",
    },
    {
      where: {
        id: subscription.id,
      },
    },
  );

  res.send();
};

/**
 * NOTE: Subscription Cancellation Email Integration
 *
 * When you create a subscription cancellation endpoint, integrate the
 * sendSubscriptionCancellationEmail function like this:
 *
 * Example:
 *
 * const cancelSubscription = async (req, res) => {
 *   try {
 *     const company = await Companies.findByPk(req.user.companyId);
 *     const adminUser = await Users.findOne({
 *       where: {
 *         CompanyId: company.id,
 *         role: { [Op.or]: ["super-admin"] }
 *       }
 *     });
 *
 *     // Perform cancellation logic here...
 *
 *     // Send cancellation email
 *     if (adminUser) {
 *       const companyAddress = `${company.address1}${company.address2 ? ", " + company.address2 : ""}, ${company.city}, ${company.zipCode}, ${company.country}`;
 *
 *       await sendSubscriptionCancellationEmail({
 *         to: adminUser.email,
 *         customerName: adminUser.fullname,
 *         companyName: company.name,
 *         companyEmail: company.email,
 *         companyAddress: companyAddress,
 *         companyPhone: company.phoneNumber,
 *         cancellationDate: new Date(),
 *         isTrialPeriod: company.subscriptionType === "free trial",
 *       });
 *     }
 *
 *     res.json({ message: "Subscription cancelled successfully" });
 *   } catch (error) {
 *     console.error("Failed to cancel subscription:", error);
 *     res.status(500).json({ message: "Failed to cancel subscription" });
 *   }
 * };
 */

const createCheckoutSession = async (req, res) => {
  const permissions = ["super-admin"];
  if (!permissions.includes(req.user?.role))
    return res.status(403).json({ message: "Forbidden" });

  try {
    const company = await Companies.findByPk(req.user.companyId);
    if (!company) return res.status(404).json({ message: "Company not found" });

    const subscription = await Subscriptions.findOne({
      where: {
        CompanyId: company.id,
      },
      order: [["createdAt", "DESC"]],
    });

    if (!subscription)
      return res.status(404).json({ message: "Subscription not found" });

    if (
      !subscription.userPrice ||
      !subscription.projectPrice ||
      !subscription.monthlySDSSavePrice ||
      !subscription.monthlySDSSearchPerSavePrice
    )
      return res.status(404).json({
        message: "Subscription prices not set yet, Contact the support team",
      });

    const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

    const price =
      subscription.usersCount * subscription.userPrice +
      subscription.projectsCount * subscription.projectPrice +
      subscription.monthlySDSSaveCount * subscription.monthlySDSSavePrice +
      subscription.monthlySDSSaveCount *
        subscription.monthlySDSSearchPerSavePrice;

    const session = await stripe.checkout.sessions.create({
      payment_method_types: ["card"],
      line_items: [
        {
          price_data: {
            currency: "usd",
            product_data: {
              name: "NordSafe EHS Subscription",
            },
            unit_amount: price * 100,
          },
          quantity: 1,
        },
      ],
      mode: "payment",
      success_url: `${process.env.FRONTEND_URL}/company-settings/subscription?success=true`,
      cancel_url: `${process.env.FRONTEND_URL}/company-settings/subscription?canceled=true`,
      customer_email: company.email,
      metadata: {
        companyId: company.id,
      },
    });

    return res.json({ url: session.url });
  } catch (error) {
    console.error("Error creating checkout session:", error);
    return res.status(500).json({
      message: "Failed to create checkout session",
    });
  }
};

const request = async (req, res) => {
  const permissions = ["super-admin"];
  if (!permissions.includes(req.user?.role))
    return res.status(403).json({ message: "Forbidden" });

  const { users, projects, sdsSearch, sdsSave } = req.body;

  if (
    users === undefined ||
    users === null ||
    projects === undefined ||
    projects === null ||
    sdsSearch === undefined ||
    sdsSearch === null ||
    sdsSave === undefined ||
    sdsSave === null
  )
    return res.status(400).json({ message: "All fields are required" });

  if (users < 5)
    return res.status(400).json({ message: "Minimum users count is 5" });

  if (projects < 1)
    return res.status(400).json({ message: "Minimum projects count is 1" });

  if (sdsSearch < 20)
    return res.status(400).json({ message: "Minimum SDS search count is 20" });

  if (sdsSave < 0)
    return res.status(400).json({
      message: "SDS save count cannot be negative",
    });

  try {
    const companyId = req.user.companyId;

    const subscription = await Subscriptions.findOne({
      where: {
        CompanyId: companyId,
      },
      order: [["createdAt", "DESC"]],
    });

    if (!subscription)
      return res.status(404).json({ message: "Subscription not found" });

    if (
      subscription.usersCount === users &&
      subscription.projectsCount === projects &&
      subscription.monthlySDSSearchCount === sdsSearch &&
      subscription.monthlySDSSaveCount === sdsSave
    )
      return res.status(400).json({
        message: "No changes detected. Please modify at least one value.",
      });

    if (subscription.subscriptionType == "free trial")
      await Subscriptions.update(
        {
          usersCount: users,
          projectsCount: projects,
          monthlySDSSearchCount: sdsSearch,
          monthlySDSSaveCount: sdsSave,
          userPrice: null,
          projectPrice: null,
          SDSSavePrice: null,
          SDSSearchPerSavePrice: null,
        },
        {
          where: {
            id: subscription.id,
          },
        },
      );
    else
      await Subscriptions.create({
        usersCount: users,
        projectsCount: projects,
        monthlySDSSearchCount: sdsSearch,
        monthlySDSSaveCount: sdsSave,
        CompanyId: companyId,
        userPrice: null,
        projectPrice: null,
        SDSSavePrice: null,
        SDSSearchPerSavePrice: null,
      });

    return res.json({ message: "Subscription request sent successfully" });
  } catch (error) {
    return res.status(500).json({
      message: "Failed to send the request",
    });
  }
};

module.exports = {
  getSubscriptionDetails,
  webhook,
  createCheckoutSession,
  request,
};
