import { Request, Response, NextFunction } from "express"
import {
  prisma,
  createCheckoutSession,
  getSubscription as fetchSubscription,
  cancelSubscription as cancelStripeSubscription,
} from "@codeflash-ai/common"
import * as Sentry from "@sentry/node"
import { logger } from "../utils/logger.js"
import { missingRequiredFields, subscriptionNotFound } from "../exceptions/index.js"

// Dependencies interface for easier testing
export interface SubscriptionDependencies {
  prisma: {
    subscriptions: {
      findUnique: (params: any) => Promise<any>
    }
  }
  createCheckoutSession: typeof createCheckoutSession
  fetchSubscription: typeof fetchSubscription // Add this
  cancelStripeSubscription: typeof cancelStripeSubscription
  Sentry: {
    captureException: (error: any) => void
  }
}

// Default dependencies
let dependencies: SubscriptionDependencies = {
  prisma,
  createCheckoutSession,
  fetchSubscription,
  cancelStripeSubscription,
  Sentry,
}

// For testing - allow dependency injection
export function setSubscriptionDependencies(deps: Partial<SubscriptionDependencies>) {
  dependencies = { ...dependencies, ...deps }
}

export function resetSubscriptionDependencies() {
  dependencies = {
    prisma,
    createCheckoutSession,
    fetchSubscription,
    cancelStripeSubscription,
    Sentry,
  }
}

// Get a user's subscription details
export async function getSubscription(req: Request, res: Response, next: NextFunction) {
  const userId = req.query.userId as string

  if (!userId) {
    next(missingRequiredFields("userId"))
    return
  }

  try {
    // Get subscription with usage data (includes lazy reset)
    const subscription = await dependencies.fetchSubscription(userId)

    if (!subscription) {
      next(subscriptionNotFound(userId))
      return
    }

    return res.json({
      plan: subscription.plan_type,
      status: subscription.subscription_status,
      usageCount: subscription.optimizations_used,
      usageLimit: subscription.optimizations_limit,
      renewalDate: subscription.current_period_end,
      totalLifetimeOptimizations: subscription.total_lifetime_optimizations,
    })
  } catch (error) {
    logger.errorWithSentry("Error getting subscription", req, {}, error as Error)
    dependencies.Sentry.captureException(error)
    next(error) // Pass errors to the error handler
  }
}

// Create a checkout session for upgrading subscription
export async function createCheckout(req: Request, res: Response, next: NextFunction) {
  const { userId, priceId, successUrl, cancelUrl, period } = req.body

  if (!userId || !priceId) {
    next(missingRequiredFields("userId, priceId"))
    return
  }

  try {
    // Use the common function with options object
    const checkoutUrl = await dependencies.createCheckoutSession(userId, priceId, {
      successUrl: successUrl || `${process.env.WEBAPP_URL}/app/billing?success=true`,
      cancelUrl: cancelUrl || `${process.env.WEBAPP_URL}/app/billing?canceled=true`,
      period: period || (priceId === process.env.STRIPE_PRO_PRICE_YEARLY_ID ? "yearly" : "monthly"),
    })

    return res.json({ url: checkoutUrl })
  } catch (error) {
    logger.errorWithSentry(
      "Error creating checkout session",
      req,
      { successUrl, cancelUrl, period },
      error as Error,
    )
    dependencies.Sentry.captureException(error)
    next(error) // Pass errors to the error handler
  }
}

// Cancel a subscription
export async function cancelSubscription(req: Request, res: Response, next: NextFunction) {
  const { userId } = req.body

  if (!userId) {
    next(missingRequiredFields("userId"))
    return
  }

  try {
    // Use the common function for cancellation
    await dependencies.cancelStripeSubscription(userId)
    return res.json({ status: "canceled" })
  } catch (error) {
    logger.errorWithSentry("Error canceling subscription", req, {}, error as Error)
    dependencies.Sentry.captureException(error)
    next(error) // Pass errors to the error handler
  }
}
