/**
 * Admin Analytics Routes
 *
 * Admin endpoints for system analytics and metrics
 */

import { Router, Request, Response } from 'express';
import { PrismaClient, TranslationJobStatus } from '@prisma/client';
import { authenticateAdmin } from '../../middleware/auth';
import { logger } from '../../utils/logger';

const router = Router();
const prisma = new PrismaClient();

/**
 * Dashboard metrics response
 */
interface DashboardMetrics {
  users: {
    total: number;
    active: number;
    new30Days: number;
  };
  subscriptions: {
    active: number;
    byTier: Record<string, number>;
  };
  translations: {
    total: number;
    today: number;
    thisMonth: number;
    completed: number;
    failed: number;
    avgProcessingTimeMs: number;
  };
  revenue: {
    total: string;
    thisMonth: string;
    lastMonth: string;
  };
  system: {
    errorRate: number;
    avgTokensPerJob: number;
  };
}

/**
 * Revenue data point for time series
 */
interface RevenueDataPoint {
  date: string;
  amount: string;
  subscriptions: number;
  transactions: number;
}

/**
 * Usage data point for time series
 */
interface UsageDataPoint {
  date: string;
  translations: number;
  tokensUsed: number;
  uniqueUsers: number;
}

/**
 * GET /v1/admin/analytics/dashboard
 * Get high-level dashboard metrics
 */
router.get('/dashboard', authenticateAdmin, async (_req: Request, res: Response) => {
  try {
    const now = new Date();
    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
    const lastMonthStart = new Date(now.getFullYear(), now.getMonth() - 1, 1);
    const lastMonthEnd = new Date(now.getFullYear(), now.getMonth(), 0, 23, 59, 59);
    const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);

    // Execute all queries in parallel for performance
    const [
      totalUsers,
      activeUsers,
      newUsers30Days,
      activeSubscriptions,
      subscriptionsByTier,
      totalTranslations,
      translationsToday,
      translationsThisMonth,
      completedTranslations,
      failedTranslations,
      avgProcessingTime,
      totalRevenue,
      revenueThisMonth,
      revenueLastMonth,
      totalJobs,
      avgTokens,
    ] = await Promise.all([
      // User metrics
      prisma.user.count(),
      prisma.user.count({ where: { status: 'active' } }),
      prisma.user.count({ where: { created_at: { gte: thirtyDaysAgo } } }),

      // Subscription metrics
      prisma.subscription.count({ where: { status: 'active' } }),
      prisma.subscription.groupBy({
        by: ['plan_tier'],
        where: { status: 'active' },
        _count: { id: true },
      }),

      // Translation metrics
      prisma.translationJob.count(),
      prisma.translationJob.count({ where: { created_at: { gte: today } } }),
      prisma.translationJob.count({ where: { created_at: { gte: monthStart } } }),
      prisma.translationJob.count({ where: { status: TranslationJobStatus.completed } }),
      prisma.translationJob.count({ where: { status: TranslationJobStatus.failed } }),
      prisma.translationJob.aggregate({
        where: { status: TranslationJobStatus.completed, processing_time_ms: { not: null } },
        _avg: { processing_time_ms: true },
      }),

      // Revenue metrics
      prisma.payment.aggregate({
        where: { status: 'completed' },
        _sum: { amount: true },
      }),
      prisma.payment.aggregate({
        where: { status: 'completed', created_at: { gte: monthStart } },
        _sum: { amount: true },
      }),
      prisma.payment.aggregate({
        where: { status: 'completed', created_at: { gte: lastMonthStart, lte: lastMonthEnd } },
        _sum: { amount: true },
      }),

      // System metrics
      prisma.translationJob.count({ where: { status: { in: [TranslationJobStatus.completed, TranslationJobStatus.failed] } } }),
      prisma.translationJob.aggregate({
        where: { status: TranslationJobStatus.completed },
        _avg: { tokens_used: true },
      }),
    ]);

    // Calculate subscription counts by tier (dynamic - handles any tier slug)
    const tierCounts: Record<string, number> = {};
    subscriptionsByTier.forEach((group) => {
      tierCounts[group.plan_tier] = group._count.id;
    });

    // Calculate error rate
    const errorRate = totalJobs > 0 ? (failedTranslations / totalJobs) * 100 : 0;

    const metrics: DashboardMetrics = {
      users: {
        total: totalUsers,
        active: activeUsers,
        new30Days: newUsers30Days,
      },
      subscriptions: {
        active: activeSubscriptions,
        byTier: tierCounts,
      },
      translations: {
        total: totalTranslations,
        today: translationsToday,
        thisMonth: translationsThisMonth,
        completed: completedTranslations,
        failed: failedTranslations,
        avgProcessingTimeMs: Math.round(avgProcessingTime._avg.processing_time_ms ?? 0),
      },
      revenue: {
        total: totalRevenue._sum.amount?.toString() ?? '0',
        thisMonth: revenueThisMonth._sum.amount?.toString() ?? '0',
        lastMonth: revenueLastMonth._sum.amount?.toString() ?? '0',
      },
      system: {
        errorRate: parseFloat(errorRate.toFixed(2)),
        avgTokensPerJob: Math.round(avgTokens._avg.tokens_used ?? 0),
      },
    };

    res.json(metrics);
  } catch (error) {
    logger.error('Error fetching dashboard metrics', { error });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to fetch dashboard metrics',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * GET /v1/admin/analytics/multilingual
 * Get multilingual plugin license analytics
 */
router.get('/multilingual', authenticateAdmin, async (_req: Request, res: Response) => {
  try {
    const now = new Date();
    const thirtyDaysFromNow = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);

    const [
      totalLicenses,
      activeLicenses,
      suspendedLicenses,
      expiredLicenses,
      expiringIn30Days,
      totalActivations,
      activeActivations,
      tierBreakdown,
    ] = await Promise.all([
      prisma.license.count({ where: { plugin: 'multilingual' } }),
      prisma.license.count({ where: { plugin: 'multilingual', status: 'active' } }),
      prisma.license.count({ where: { plugin: 'multilingual', status: 'suspended' } }),
      prisma.license.count({ where: { plugin: 'multilingual', status: 'expired' } }),
      prisma.license.count({
        where: {
          plugin: 'multilingual',
          status: 'active',
          expires_at: { gte: now, lte: thirtyDaysFromNow },
        },
      }),
      prisma.licenseActivation.count({
        where: { license: { plugin: 'multilingual' } },
      }),
      prisma.licenseActivation.count({
        where: { license: { plugin: 'multilingual' }, deactivated_at: null },
      }),
      prisma.license.groupBy({
        by: ['plan_tier'],
        where: { plugin: 'multilingual' },
        _count: { id: true },
      }),
    ]);

    const tierCounts: Record<string, number> = {};
    tierBreakdown.forEach((group) => {
      tierCounts[group.plan_tier] = group._count.id;
    });

    res.json({
      licenses: {
        total: totalLicenses,
        active: activeLicenses,
        suspended: suspendedLicenses,
        expired: expiredLicenses,
        expiringIn30Days,
      },
      sites: {
        total: totalActivations,
        active: activeActivations,
      },
      tierBreakdown: tierCounts,
    });
  } catch (error) {
    logger.error('Error fetching multilingual analytics', { error });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to fetch multilingual analytics',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * GET /v1/admin/analytics/international
 * Combined analytics for International Press Zone (licenses + translations)
 * Shows only users/subscriptions with plugin='international'
 */
router.get('/international', authenticateAdmin, async (_req: Request, res: Response) => {
  try {
    const now = new Date();
    const thirtyDaysFromNow = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);

    const [
      totalLicenses,
      activeLicenses,
      expiringIn30Days,
      totalActivations,
      activeActivations,
      tierBreakdown,
      // User counts scoped to international plugin subscribers
      totalPluginUsers,
      activePluginSubscriptions,
    ] = await Promise.all([
      prisma.license.count({ where: { plugin: 'international' } }),
      prisma.license.count({ where: { plugin: 'international', status: 'active' } }),
      prisma.license.count({
        where: {
          plugin: 'international',
          status: 'active',
          expires_at: { gte: now, lte: thirtyDaysFromNow },
        },
      }),
      prisma.licenseActivation.count({
        where: { license: { plugin: 'international' } },
      }),
      prisma.licenseActivation.count({
        where: { license: { plugin: 'international' }, deactivated_at: null },
      }),
      prisma.license.groupBy({
        by: ['plan_tier'],
        where: { plugin: 'international' },
        _count: { id: true },
      }),
      // Count users who have a subscription for this plugin
      prisma.subscription.count({
        where: { plugin: 'international' },
      }),
      prisma.subscription.count({
        where: { plugin: 'international', status: 'active' },
      }),
    ]);

    const tierCounts: Record<string, number> = {};
    tierBreakdown.forEach((group) => {
      tierCounts[group.plan_tier] = group._count.id;
    });

    res.json({
      users: {
        total: totalPluginUsers,
        active: activePluginSubscriptions,
      },
      licenses: {
        total: totalLicenses,
        active: activeLicenses,
        expiringIn30Days,
      },
      sites: {
        total: totalActivations,
        active: activeActivations,
      },
      tierBreakdown: tierCounts,
    });
  } catch (error) {
    logger.error('Error fetching international analytics', { error });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to fetch international analytics',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * GET /v1/admin/analytics/revenue
 * Get revenue breakdown over time
 */
router.get('/revenue', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { days = '30', groupBy: _groupBy = 'day' } = req.query;
    const daysNum = Math.min(365, Math.max(1, parseInt(days as string, 10)));

    const startDate = new Date();
    startDate.setDate(startDate.getDate() - daysNum);
    startDate.setHours(0, 0, 0, 0);

    // Get payments grouped by date
    const payments = await prisma.payment.findMany({
      where: {
        status: 'completed',
        created_at: { gte: startDate },
      },
      select: {
        created_at: true,
        amount: true,
        subscription_id: true,
      },
      orderBy: { created_at: 'asc' },
    });

    // Group by date
    const revenueMap = new Map<string, { amount: number; subscriptions: Set<string>; transactions: number }>();

    payments.forEach((payment) => {
      const dateKey = payment.created_at.toISOString().split('T')[0];
      const existing = revenueMap.get(dateKey) || { amount: 0, subscriptions: new Set<string>(), transactions: 0 };
      existing.amount += parseFloat(payment.amount.toString());
      if (payment.subscription_id) {
        existing.subscriptions.add(payment.subscription_id);
      }
      existing.transactions += 1;
      revenueMap.set(dateKey, existing);
    });

    // Convert to array
    const revenueData: RevenueDataPoint[] = Array.from(revenueMap.entries())
      .map(([date, data]) => ({
        date,
        amount: data.amount.toFixed(2),
        subscriptions: data.subscriptions.size,
        transactions: data.transactions,
      }))
      .sort((a, b) => a.date.localeCompare(b.date));

    res.json(revenueData);
  } catch (error) {
    logger.error('Error fetching revenue analytics', { error });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to fetch revenue analytics',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * GET /v1/admin/analytics/usage
 * Get usage statistics over time
 */
router.get('/usage', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { days = '30' } = req.query;
    const daysNum = Math.min(365, Math.max(1, parseInt(days as string, 10)));

    const startDate = new Date();
    startDate.setDate(startDate.getDate() - daysNum);
    startDate.setHours(0, 0, 0, 0);

    // Get translation jobs grouped by date
    const jobs = await prisma.translationJob.findMany({
      where: {
        created_at: { gte: startDate },
      },
      select: {
        created_at: true,
        tokens_used: true,
        user_id: true,
        model: true,
      },
      orderBy: { created_at: 'asc' },
    });

    // Group by date
    const usageMap = new Map<string, { translations: number; tokensUsed: number; uniqueUsers: Set<string> }>();

    jobs.forEach((job) => {
      const dateKey = job.created_at.toISOString().split('T')[0];
      const existing = usageMap.get(dateKey) || { translations: 0, tokensUsed: 0, uniqueUsers: new Set<string>() };
      existing.translations += 1;
      existing.tokensUsed += job.tokens_used;
      existing.uniqueUsers.add(job.user_id);
      usageMap.set(dateKey, existing);
    });

    // Convert to array
    const usageData: UsageDataPoint[] = Array.from(usageMap.entries())
      .map(([date, data]) => ({
        date,
        translations: data.translations,
        tokensUsed: data.tokensUsed,
        uniqueUsers: data.uniqueUsers.size,
      }))
      .sort((a, b) => a.date.localeCompare(b.date));

    res.json(usageData);
  } catch (error) {
    logger.error('Error fetching usage analytics', { error });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to fetch usage analytics',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * GET /v1/admin/analytics/jobs
 * Get job-specific analytics
 */
router.get('/jobs', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { days = '7' } = req.query;
    const daysNum = Math.min(365, Math.max(1, parseInt(days as string, 10)));

    const startDate = new Date();
    startDate.setDate(startDate.getDate() - daysNum);
    startDate.setHours(0, 0, 0, 0);

    // Get job statistics
    const [
      totalJobs,
      completedJobs,
      failedJobs,
      pendingJobs,
      processingJobs,
      cancelledJobs,
      avgProcessingTime,
      avgTokensUsed,
      jobsByLanguage,
    ] = await Promise.all([
      prisma.translationJob.count({ where: { created_at: { gte: startDate } } }),
      prisma.translationJob.count({ where: { status: TranslationJobStatus.completed, created_at: { gte: startDate } } }),
      prisma.translationJob.count({ where: { status: TranslationJobStatus.failed, created_at: { gte: startDate } } }),
      prisma.translationJob.count({ where: { status: TranslationJobStatus.pending, created_at: { gte: startDate } } }),
      prisma.translationJob.count({ where: { status: TranslationJobStatus.processing, created_at: { gte: startDate } } }),
      prisma.translationJob.count({ where: { status: TranslationJobStatus.cancelled, created_at: { gte: startDate } } }),
      prisma.translationJob.aggregate({
        where: { status: TranslationJobStatus.completed, processing_time_ms: { not: null }, created_at: { gte: startDate } },
        _avg: { processing_time_ms: true },
      }),
      prisma.translationJob.aggregate({
        where: { status: TranslationJobStatus.completed, created_at: { gte: startDate } },
        _avg: { tokens_used: true },
      }),
      prisma.translationJob.groupBy({
        by: ['target_lang'],
        where: { created_at: { gte: startDate } },
        _count: { id: true },
        orderBy: { _count: { id: 'desc' } },
        take: 10,
      }),
    ]);

    const successRate = totalJobs > 0 ? (completedJobs / totalJobs) * 100 : 0;
    const failureRate = totalJobs > 0 ? (failedJobs / totalJobs) * 100 : 0;

    res.json({
      period: {
        days: daysNum,
        startDate: startDate.toISOString(),
        endDate: new Date().toISOString(),
      },
      totals: {
        total: totalJobs,
        completed: completedJobs,
        failed: failedJobs,
        pending: pendingJobs,
        processing: processingJobs,
        cancelled: cancelledJobs,
      },
      rates: {
        successRate: parseFloat(successRate.toFixed(2)),
        failureRate: parseFloat(failureRate.toFixed(2)),
      },
      averages: {
        processingTimeMs: Math.round(avgProcessingTime._avg.processing_time_ms ?? 0),
        tokensUsed: Math.round(avgTokensUsed._avg.tokens_used ?? 0),
      },
      topLanguages: jobsByLanguage.map((lang) => ({
        language: lang.target_lang,
        count: lang._count.id,
      })),
    });
  } catch (error) {
    logger.error('Error fetching job analytics', { error });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to fetch job analytics',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * GET /v1/admin/analytics/overview
 * Alias to /dashboard for backward compatibility
 */
router.get('/overview', authenticateAdmin, async (_req: Request, res: Response) => {
  return res.redirect('/v1/admin/analytics/dashboard');
});

// Alias: /stats points to /dashboard for backward compatibility
router.get('/stats', authenticateAdmin, async (_req: Request, res: Response) => {
  // Redirect to dashboard endpoint
  return res.redirect('/v1/admin/analytics/dashboard');
});

export default router;
