/**
 * Package Access Middleware
 * Enforces module, feature, and AI model access based on the company's subscription package.
 * Super-admin users bypass all checks.
 */

import { Request, Response, NextFunction } from 'express';
import { getCompanyPackageAccess } from '../services/packageAssignment';

/**
 * Module slugs that are always accessible regardless of subscription.
 * Foundation and Brand modules are core platform capabilities
 * that every customer gets by default.
 */
const MANDATORY_MODULE_SLUGS = new Set([
  'business_profile_module',
  'founders_module',
  'employees_module',
  'products_module',
  'icp_module',
  'competitors_module',
  'brand_module',
  'brand_strategy_module',
  'visual_identity_module',
  'brand_manual_module',
  'brand_assets_module',
]);

// Cache for company access lookups (5-minute TTL)
const accessCache = new Map<string, { access: any; expiry: number }>();
const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes

/**
 * Get cached company package access, fetching from DB on cache miss.
 */
async function getCachedAccess(companyId: string) {
  const now = Date.now();
  const cached = accessCache.get(companyId);
  if (cached && now < cached.expiry) {
    return cached.access;
  }

  const access = await getCompanyPackageAccess(companyId);
  accessCache.set(companyId, { access, expiry: now + CACHE_TTL_MS });
  return access;
}

/**
 * Invalidate the access cache for a company (call when subscription changes).
 */
export function invalidateAccessCache(companyId: string) {
  accessCache.delete(companyId);
}

/**
 * Middleware factory: require that the company's subscription includes a specific module.
 * Usage: app.use('/api/blogs', requireModuleAccess('blog_module'))
 */
export function requireModuleAccess(moduleSlug: string) {
  return async (req: Request, res: Response, next: NextFunction) => {
    // Skip if no user (shouldn't happen after auth middleware)
    if (!req.user) {
      next();
      return;
    }

    // Super-admin bypasses all checks
    if (req.user.role === 'super-admin') {
      next();
      return;
    }

    // Mandatory modules are always accessible (Foundation + Brand)
    if (MANDATORY_MODULE_SLUGS.has(moduleSlug)) {
      next();
      return;
    }

    const companyId = req.params.companyId || req.body.companyId || req.user.companyIds?.[0];
    if (!companyId) {
      // No company context — allow through (will be caught by other middleware)
      next();
      return;
    }

    try {
      const access = await getCachedAccess(companyId);

      // No subscription found — allow through (caught by requireActiveSubscription)
      if (!access) {
        next();
        return;
      }

      // If modules array is empty, subscription exists but no modules are assigned
      // This means no module access at all (expired/cancelled subscription)
      if (access.modules.length === 0) {
        res.status(403).json({
          error: 'MODULE_NOT_INCLUDED',
          message: 'No modules are included in your subscription plan.',
          moduleSlug,
        });
        return;
      }

      // Check if the module is included
      if (!access.modules.includes(moduleSlug)) {
        res.status(403).json({
          error: 'MODULE_NOT_INCLUDED',
          message: `The module "${moduleSlug}" is not included in your subscription plan. Please upgrade to access this feature.`,
          moduleSlug,
        });
        return;
      }

      next();
    } catch (error) {
      console.error('[PackageAccess] Error checking module access:', error);
      // On error, allow through — don't block on DB failure
      next();
    }
  };
}

/**
 * Middleware factory: require that the company's subscription includes a specific feature.
 * Usage: requireFeatureAccess('api_access')(req, res, next)
 */
export function requireFeatureAccess(featureSlug: string) {
  return async (req: Request, res: Response, next: NextFunction) => {
    if (!req.user) {
      next();
      return;
    }

    if (req.user.role === 'super-admin') {
      next();
      return;
    }

    const companyId = req.params.companyId || req.body.companyId || req.user.companyIds?.[0];
    if (!companyId) {
      next();
      return;
    }

    try {
      const access = await getCachedAccess(companyId);
      if (!access) {
        next();
        return;
      }

      if (!access.features.includes(featureSlug)) {
        res.status(403).json({
          error: 'FEATURE_NOT_INCLUDED',
          message: `The feature "${featureSlug}" is not included in your subscription plan. Please upgrade to access this feature.`,
          featureSlug,
        });
        return;
      }

      next();
    } catch (error) {
      console.error('[PackageAccess] Error checking feature access:', error);
      next();
    }
  };
}

/**
 * Middleware factory: require that the company's subscription includes a specific AI model.
 * Usage: requireAIModelAccess('claude_sonnet_4_6')(req, res, next)
 */
export function requireAIModelAccess(modelSlug: string) {
  return async (req: Request, res: Response, next: NextFunction) => {
    if (!req.user) {
      next();
      return;
    }

    if (req.user.role === 'super-admin') {
      next();
      return;
    }

    const companyId = req.params.companyId || req.body.companyId || req.user.companyIds?.[0];
    if (!companyId) {
      next();
      return;
    }

    try {
      const access = await getCachedAccess(companyId);
      if (!access) {
        next();
        return;
      }

      // If aiModels is empty, fall back to allowing all (legacy/no restriction)
      if (access.aiModels.length === 0) {
        next();
        return;
      }

      if (!access.aiModels.includes(modelSlug)) {
        res.status(403).json({
          error: 'AI_MODEL_NOT_INCLUDED',
          message: `The AI model "${modelSlug}" is not included in your subscription plan. Please upgrade to access this model.`,
          modelSlug,
        });
        return;
      }

      next();
    } catch (error) {
      console.error('[PackageAccess] Error checking AI model access:', error);
      next();
    }
  };
}

/**
 * Map of API route prefixes to their corresponding module slugs.
 * Used by the global module access middleware to enforce subscription-based module gating.
 */
export const ROUTE_MODULE_MAP: Record<string, string> = {
  // ── Foundation ──
  '/api/business-profiles': 'business_profile_module',
  '/api/founders': 'founders_module',
  '/api/employees': 'employees_module',
  '/api/products': 'products_module',
  '/api/icps': 'icp_module',
  '/api/personas': 'icp_module',
  '/api/competitors': 'competitors_module',

  // ── Brand ──
  '/api/brands': 'brand_module',
  '/api/brand-strategies': 'brand_strategy_module',
  '/api/visual-identities': 'visual_identity_module',
  '/api/brand-manuals': 'brand_manual_module',
  '/api/brand-assets': 'brand_assets_module',
  '/api/stationery': 'stationery_module',
  '/api/hr-assets': 'hr_assets_module',

  // ── Content ──
  '/api/blogs': 'blog_module',
  '/api/case-studies': 'case_studies_module',
  '/api/testimonials': 'testimonials_module',
  '/api/seo-pages': 'seo_module',
  '/api/website-planners': 'website_planner_module',
  '/api/newsletters': 'newsletter_module',
  '/api/faqs': 'faq_module',
  '/api/social-media': 'social_media_module',

  // ── Sales ──
  '/api/landing-pages': 'landing_pages_module',
  '/api/whatsapp-nurturing': 'whatsapp_module',
  '/api/sales-scripts': 'sales_scripts_module',
  '/api/sales-collateral': 'sales_collateral_module',
  '/api/video-content': 'video_content_module',
  '/api/audio-contents': 'audio_content_module',
  '/api/books': 'books_module',
  '/api/intro-scripts': 'intro_scripts_module',

  // ── Marketing ──
  '/api/ads': 'campaigns_module',
  '/api/pr': 'pr_campaigns_module',
  '/api/email-templates': 'email_templates_module',
  '/api/courses': 'courses_module',
  '/api/events': 'events_module',
  '/api/guerrilla-marketing': 'guerrilla_module',
  '/api/interview-media-prep': 'interview_module',
  '/api/speaking-engagements': 'speaking_module',
  '/api/moat-analysis': 'moat_module',
  '/api/marketing-calendars': 'marketing_calendar_module',
  '/api/marketing-channels': 'marketing_channels_module',
  '/api/geo-optimization': 'geo_optimization_module',
  '/api/influencers': 'influencer_module',
  '/api/gmb-locations': 'gmb_module',
  '/api/wikipedia-profiles': 'gmb_module',

  // ── Programs ──
  '/api/loyalty-programmes': 'loyalty_programme_module',
  '/api/membership-plans': 'membership_plans_module',
  '/api/referral-programmes': 'referral_programme_module',
  '/api/referral-tracking': 'referral_tracking_module',
  '/api/sops': 'sops_module',

  // ── Ops ──
  '/api/legal-documents': 'legal_documents_module',

  // ── Publishing ──
  '/api/magazine-sponsorship': 'magazine_module',

  // ── Funding ──
  '/api/pitch-decks': 'pitch_decks_module',
  '/api/investors': 'pitch_decks_module', // investors belong to funding module
  '/api/funding-rounds': 'pitch_decks_module', // funding rounds belong to funding module
  '/api/presentations': 'presentations_module',

  // ── Sales Performance ──
  '/api/commission-tracker': 'commission_tracker_module',
  '/api/sales-targets': 'sales_targets_module',
  '/api/sales-playbooks': 'sales_playbooks_module',

  // ── Other ──
  '/api/job-postings': 'job_postings_module',
  '/api/financial-models': 'financial_models_module',
  '/api/image-generations': 'image_generation', // AI feature, treated as module
  '/api/ai-processing': 'ai_processing_module',
};