const express = require("express");
const { authenticateToken, requireVerifiedEmail } = require("../middleware/auth");
const { User, Item } = require("../models");
const StripeService = require("../services/stripeService");
const StripeWebhookService = require("../services/stripeWebhookService");
const emailServices = require("../services/email");
const logger = require("../utils/logger");
const router = express.Router();

// Get checkout session status
router.get("/checkout-session/:sessionId", async (req, res, next) => {
  try {
    const { sessionId } = req.params;

    const session = await StripeService.getCheckoutSession(sessionId);

    const reqLogger = logger.withRequestId(req.id);
    reqLogger.info("Stripe checkout session retrieved", {
      sessionId: sessionId,
      status: session.status,
      payment_status: session.payment_status,
      metadata: session.metadata,
    });

    res.json({
      status: session.status,
      payment_status: session.payment_status,
      customer_email: session.customer_details?.email,
      setup_intent: session.setup_intent,
      metadata: session.metadata,
    });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Stripe checkout session retrieval failed", {
      error: error.message,
      stack: error.stack,
      sessionId: req.params.sessionId,
    });
    next(error);
  }
});

// Create connected account
router.post("/accounts", authenticateToken, requireVerifiedEmail, async (req, res, next) => {
  try {
    const user = await User.findByPk(req.user.id);

    if (!user) {
      return res.status(404).json({ error: "User not found" });
    }

    // Check if user already has a connected account
    if (user.stripeConnectedAccountId) {
      return res
        .status(400)
        .json({ error: "User already has a connected account" });
    }

    // Create connected account
    const account = await StripeService.createConnectedAccount({
      email: user.email,
      country: "US", // You may want to make this configurable
    });

    // Update user with account ID
    await user.update({
      stripeConnectedAccountId: account.id,
    });

    const reqLogger = logger.withRequestId(req.id);
    reqLogger.info("Stripe connected account created", {
      userId: req.user.id,
      stripeConnectedAccountId: account.id,
    });

    res.json({
      stripeConnectedAccountId: account.id,
      success: true,
    });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Stripe connected account creation failed", {
      error: error.message,
      stack: error.stack,
      userId: req.user.id,
    });
    next(error);
  }
});

// Generate onboarding link
router.post("/account-links", authenticateToken, requireVerifiedEmail, async (req, res, next) => {
  let user = null;
  try {
    user = await User.findByPk(req.user.id);

    if (!user || !user.stripeConnectedAccountId) {
      return res.status(400).json({ error: "No connected account found" });
    }

    const { refreshUrl, returnUrl } = req.body;

    if (!refreshUrl || !returnUrl) {
      return res
        .status(400)
        .json({ error: "refreshUrl and returnUrl are required" });
    }

    const accountLink = await StripeService.createAccountLink(
      user.stripeConnectedAccountId,
      refreshUrl,
      returnUrl
    );

    const reqLogger = logger.withRequestId(req.id);
    reqLogger.info("Stripe account link created", {
      userId: req.user.id,
      stripeConnectedAccountId: user.stripeConnectedAccountId,
      expiresAt: accountLink.expires_at,
    });

    res.json({
      url: accountLink.url,
      expiresAt: accountLink.expires_at,
    });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Stripe account link creation failed", {
      error: error.message,
      stack: error.stack,
      userId: req.user.id,
      stripeConnectedAccountId: user?.stripeConnectedAccountId,
    });
    next(error);
  }
});

// Create account session for embedded onboarding
router.post("/account-sessions", authenticateToken, requireVerifiedEmail, async (req, res, next) => {
  let user = null;
  try {
    user = await User.findByPk(req.user.id);

    if (!user || !user.stripeConnectedAccountId) {
      return res.status(400).json({ error: "No connected account found" });
    }

    const accountSession = await StripeService.createAccountSession(
      user.stripeConnectedAccountId
    );

    const reqLogger = logger.withRequestId(req.id);
    reqLogger.info("Stripe account session created", {
      userId: req.user.id,
      stripeConnectedAccountId: user.stripeConnectedAccountId,
    });

    res.json({
      clientSecret: accountSession.client_secret,
    });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Stripe account session creation failed", {
      error: error.message,
      stack: error.stack,
      userId: req.user.id,
      stripeConnectedAccountId: user?.stripeConnectedAccountId,
    });
    next(error);
  }
});

// Get account status with reconciliation
router.get("/account-status", authenticateToken, async (req, res, next) => {
  let user = null;
  try {
    user = await User.findByPk(req.user.id);

    if (!user || !user.stripeConnectedAccountId) {
      return res.status(400).json({ error: "No connected account found" });
    }

    const accountStatus = await StripeService.getAccountStatus(
      user.stripeConnectedAccountId
    );

    const reqLogger = logger.withRequestId(req.id);
    reqLogger.info("Stripe account status retrieved", {
      userId: req.user.id,
      stripeConnectedAccountId: user.stripeConnectedAccountId,
      detailsSubmitted: accountStatus.details_submitted,
      payoutsEnabled: accountStatus.payouts_enabled,
    });

    // Reconciliation: Compare fetched status with stored User fields
    const previousPayoutsEnabled = user.stripePayoutsEnabled;
    const currentPayoutsEnabled = accountStatus.payouts_enabled;
    const requirements = accountStatus.requirements || {};

    // Check if status has changed and needs updating
    const statusChanged =
      previousPayoutsEnabled !== currentPayoutsEnabled ||
      JSON.stringify(user.stripeRequirementsCurrentlyDue || []) !==
        JSON.stringify(requirements.currently_due || []);

    if (statusChanged) {
      reqLogger.info("Reconciling account status from API call", {
        userId: req.user.id,
        previousPayoutsEnabled,
        currentPayoutsEnabled,
        previousCurrentlyDue: user.stripeRequirementsCurrentlyDue?.length || 0,
        newCurrentlyDue: requirements.currently_due?.length || 0,
      });

      // Update user with current status
      await user.update({
        stripePayoutsEnabled: currentPayoutsEnabled,
        stripeRequirementsCurrentlyDue: requirements.currently_due || [],
        stripeRequirementsPastDue: requirements.past_due || [],
        stripeDisabledReason: requirements.disabled_reason || null,
        stripeRequirementsLastUpdated: new Date(),
      });

      // If payouts just became disabled (true -> false), send notification
      if (!currentPayoutsEnabled && previousPayoutsEnabled) {
        reqLogger.warn("Payouts disabled detected during reconciliation", {
          userId: req.user.id,
          disabledReason: requirements.disabled_reason,
        });

        try {
          const disabledReason = StripeWebhookService.formatDisabledReason(
            requirements.disabled_reason
          );

          await emailServices.payment.sendPayoutsDisabledEmail(user.email, {
            ownerName: user.firstName || user.lastName,
            disabledReason,
          });

          reqLogger.info("Sent payouts disabled email during reconciliation", {
            userId: req.user.id,
          });
        } catch (emailError) {
          reqLogger.error("Failed to send payouts disabled email", {
            userId: req.user.id,
            error: emailError.message,
          });
        }
      }
    }

    res.json({
      accountId: accountStatus.id,
      detailsSubmitted: accountStatus.details_submitted,
      payoutsEnabled: accountStatus.payouts_enabled,
      capabilities: accountStatus.capabilities,
      requirements: accountStatus.requirements,
    });
  } catch (error) {
    const reqLogger = logger.withRequestId(req.id);
    reqLogger.error("Stripe account status retrieval failed", {
      error: error.message,
      stack: error.stack,
      userId: req.user.id,
      stripeConnectedAccountId: user?.stripeConnectedAccountId,
    });
    next(error);
  }
});

// Create embedded setup checkout session for collecting payment method
router.post(
  "/create-setup-checkout-session",
  authenticateToken,
  requireVerifiedEmail,
  async (req, res, next) => {
    let user = null;
    try {
      const { rentalData } = req.body;

      user = await User.findByPk(req.user.id);

      if (!user) {
        return res.status(404).json({ error: "User not found" });
      }

      // Create or get Stripe customer
      let stripeCustomerId = user.stripeCustomerId;

      if (!stripeCustomerId) {
        // Create new Stripe customer
        const customer = await StripeService.createCustomer({
          email: user.email,
          name: `${user.firstName} ${user.lastName}`,
          metadata: {
            userId: user.id.toString(),
          },
        });

        stripeCustomerId = customer.id;

        // Save customer ID to user record
        await user.update({ stripeCustomerId });
      }

      // Add rental data to metadata if provided
      const metadata = rentalData
        ? {
            rentalData: JSON.stringify(rentalData),
          }
        : {};

      const session = await StripeService.createSetupCheckoutSession({
        customerId: stripeCustomerId,
        metadata,
      });

      const reqLogger = logger.withRequestId(req.id);
      reqLogger.info("Stripe setup checkout session created", {
        userId: req.user.id,
        stripeCustomerId: stripeCustomerId,
        sessionId: session.id,
        hasRentalData: !!rentalData,
      });

      res.json({
        clientSecret: session.client_secret,
        sessionId: session.id,
      });
    } catch (error) {
      const reqLogger = logger.withRequestId(req.id);
      reqLogger.error("Stripe setup checkout session creation failed", {
        error: error.message,
        stack: error.stack,
        userId: req.user.id,
        stripeCustomerId: user?.stripeCustomerId,
      });
      next(error);
    }
  }
);

module.exports = router;
