import { Request, Response, NextFunction } from 'express';
import { BillingService } from '../services/billing.service';
import { SubscriptionTier } from '../config/billing.config';

const billingService = BillingService.getInstance();

export interface AuthenticatedRequest extends Request {
  userId?: string;
  tier?: SubscriptionTier;
  usage?: { current: number; limit: number; remaining: number; withinLimit: boolean };
  subscriptionId?: string;
}

export function requireTier(
  allowedTiers: SubscriptionTier[]
) {
  return async (
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    const { userId } = req;

    if (!userId) {
      res.status(401).json({ error: 'Authentication required' });
      return;
    }

    try {
      const userTier = await billingService.getUserTier(userId);

      if (!userTier) {
        res.status(401).json({ error: 'User tier not found' });
        return;
      }

      req.tier = userTier;

      if (!allowedTiers.includes(userTier)) {
        res.status(403).json({
          error: 'Tier not authorized',
          required: allowedTiers,
          current: userTier,
        });
        return;
      }

      next();
    } catch (error) {
      res.status(500).json({
        error: 'Failed to verify tier',
        message: error instanceof Error ? error.message : 'Unknown error',
      });
    }
  };
}

export function checkUsageLimit(
  feature: 'callMinutes' | 'smsCount'
) {
  return async (
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    const { userId, tier, usage } = req;

    if (!userId || !tier || !usage) {
      next();
      return;
    }

    if (!usage.withinLimit) {
      res.status(429).json({
        error: 'Usage limit exceeded',
        feature,
        limit: usage.limit,
        current: usage.current,
        remaining: usage.remaining,
      });
      return;
    }

    next();
  };
}

export function withUsageTracking(
  feature: 'callMinutes' | 'smsCount',
  increment: number = 1
) {
  return async (
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    const { userId, tier } = req;

    if (!userId || !tier) {
      next();
      return;
    }

    try {
      const limits = await billingService.getTierLimits(tier);
      const limit = feature === 'callMinutes' ? limits.callMinutesLimit : limits.smsCountLimit;

      // Get current usage from request context or database
      const currentUsage = (req as any).currentUsage || 0;

      req.usage = {
        current: currentUsage + increment,
        limit,
        remaining: Math.max(0, limit - currentUsage - increment),
        withinLimit: currentUsage + increment <= limit,
      };

      next();
    } catch (error) {
      res.status(500).json({
        error: 'Failed to check usage',
        message: error instanceof Error ? error.message : 'Unknown error',
      });
    }
  };
}

export function withSubscription() {
  return async (
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    const { userId, tier } = req;

    if (!userId || !tier) {
      next();
      return;
    }

    try {
      const subscription = await billingService.getUserSubscription(userId);
      
      if (subscription) {
        req.subscriptionId = subscription.id;
      }

      next();
    } catch (error) {
      res.status(500).json({
        error: 'Failed to fetch subscription',
        message: error instanceof Error ? error.message : 'Unknown error',
      });
    }
  };
}

export function requireSubscription() {
  return async (
    req: AuthenticatedRequest,
    res: Response,
    next: NextFunction
  ): Promise<void> => {
    const { userId, subscriptionId } = req;

    if (!userId) {
      res.status(401).json({ error: 'Authentication required' });
      return;
    }

    if (!subscriptionId) {
      res.status(402).json({
        error: 'Active subscription required',
      });
      return;
    }

    next();
  };
}
