/**
 * Admin User Management Routes
 *
 * Endpoints for managing users, API keys, and account status
 */

import { Router, Request, Response } from 'express';
import { PrismaClient } from '@prisma/client';
import { authenticateAdmin } from '../../middleware/auth';
import { logger } from '../../utils/logger';
import { PaginatedResponse } from '../../types';
import { generateToken } from '../../utils/encryption';
import { sendPasswordResetEmail } from '../../services/emailService';

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

/**
 * GET /v1/admin/users
 * List users with pagination, search, and filtering
 */
router.get('/', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const {
      page = '1',
      limit = '20',
      search = '',
      status,
      plan,
      sortBy = 'created_at',
      sortOrder = 'desc',
    } = req.query;

    const pageNum = Math.max(1, parseInt(page as string));
    const limitNum = Math.min(100, Math.max(1, parseInt(limit as string)));
    const skip = (pageNum - 1) * limitNum;

    // Build where clause
    const where: any = {};

    // Search by email
    if (search) {
      where.email = {
        contains: search as string,
        mode: 'insensitive',
      };
    }

    // Filter by status
    if (status) {
      where.status = status;
    }

    // Filter by plan
    if (plan) {
      where.subscriptions = {
        some: {
          plan_tier: plan,
        },
      };
    }

    // Build order clause
    const validSortFields = ['created_at', 'updated_at', 'email', 'status'];
    const sortField = validSortFields.includes(sortBy as string) ? sortBy : 'created_at';
    const orderBy = {
      [sortField as string]: sortOrder === 'asc' ? 'asc' : 'desc',
    };

    // Execute queries
    const [users, total] = await Promise.all([
      prisma.user.findMany({
        where,
        skip,
        take: limitNum,
        orderBy,
        include: {
          subscriptions: true,
          _count: {
            select: {
              api_keys: true,
              translation_jobs: true,
              payments: true,
            },
          },
        },
      }),
      prisma.user.count({ where }),
    ]);

    // Calculate pagination metadata
    const totalPages = Math.ceil(total / limitNum);

    const response: PaginatedResponse<any> = {
      data: users.map((user) => ({
        id: user.id,
        email: user.email,
        emailVerified: user.email_verified,
        status: user.status,
        subscription: user.subscriptions[0]
          ? {
              plan: user.subscriptions[0].plan_tier,
              billingCycle: user.subscriptions[0].billing_cycle,
              status: user.subscriptions[0].status,
              currentPeriodEnd: user.subscriptions[0].current_period_end.toISOString(),
              cancelAtPeriodEnd: user.subscriptions[0].cancel_at_period_end,
            }
          : null,
        stats: {
          apiKeys: user._count.api_keys,
          translationJobs: user._count.translation_jobs,
          payments: user._count.payments,
        },
        createdAt: user.created_at.toISOString(),
        updatedAt: user.updated_at.toISOString(),
      })),
      pagination: {
        page: pageNum,
        limit: limitNum,
        total,
        totalPages,
        hasNext: pageNum < totalPages,
        hasPrev: pageNum > 1,
      },
    };

    res.json(response);
  } catch (error) {
    logger.error('Error fetching users list', { error, adminId: req.admin?.id });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to fetch users',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * GET /v1/admin/users/:id
 * Get detailed information about a specific user
 */
router.get('/:id', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { id } = req.params;

    const user = await prisma.user.findUnique({
      where: { id },
      include: {
        subscriptions: true,
        api_keys: {
          orderBy: { created_at: 'desc' },
        },
        translation_jobs: {
          take: 10,
          orderBy: { created_at: 'desc' },
        },
        payments: {
          take: 10,
          orderBy: { created_at: 'desc' },
        },
        credit_transactions: {
          take: 10,
          orderBy: { created_at: 'desc' },
        },
      },
    });

    if (!user) {
      res.status(404).json({
        error: true,
        code: 'USER_NOT_FOUND',
        message: 'User not found',
        timestamp: new Date().toISOString(),
      });
      return;
    }

    // Calculate credit balance from latest transaction
    const latestCreditTx = await prisma.creditTransaction.findFirst({
      where: { user_id: id },
      orderBy: { ledger_sequence: 'desc' },
    });

    const creditBalance = latestCreditTx?.balance_after || 0;

    const activeSubscription = user.subscriptions.find(s => s.status === 'active') || user.subscriptions[0];
    res.json({
      id: user.id,
      email: user.email,
      emailVerified: user.email_verified,
      status: user.status,
      subscription: activeSubscription
        ? {
            id: activeSubscription.id,
            plan: activeSubscription.plan_tier,
            billingCycle: activeSubscription.billing_cycle,
            status: activeSubscription.status,
            paypalSubscriptionId: activeSubscription.paypal_subscription_id,
            currentPeriodStart: activeSubscription.current_period_start.toISOString(),
            currentPeriodEnd: activeSubscription.current_period_end.toISOString(),
            cancelAtPeriodEnd: activeSubscription.cancel_at_period_end,
            createdAt: activeSubscription.created_at.toISOString(),
            updatedAt: activeSubscription.updated_at.toISOString(),
          }
        : null,
      creditBalance,
      apiKeys: user.api_keys.map((key) => ({
        id: key.id,
        name: key.name,
        prefix: key.prefix,
        isActive: key.is_active,
        lastUsedAt: key.last_used_at?.toISOString() || null,
        createdAt: key.created_at.toISOString(),
      })),
      recentJobs: user.translation_jobs.map((job) => ({
        id: job.id,
        status: job.status,
        sourceLang: job.source_lang,
        targetLang: job.target_lang,
        model: job.model,
        tokensUsed: job.tokens_used,
        cost: job.cost.toString(),
        createdAt: job.created_at.toISOString(),
        completedAt: job.completed_at?.toISOString() || null,
      })),
      recentPayments: user.payments.map((payment) => ({
        id: payment.id,
        amount: payment.amount.toString(),
        currency: payment.currency,
        status: payment.status,
        type: payment.type,
        createdAt: payment.created_at.toISOString(),
      })),
      recentCreditTransactions: user.credit_transactions.map((tx) => ({
        id: tx.id,
        type: tx.type,
        amount: tx.amount,
        balanceAfter: tx.balance_after,
        description: tx.description,
        createdAt: tx.created_at.toISOString(),
      })),
      createdAt: user.created_at.toISOString(),
      updatedAt: user.updated_at.toISOString(),
    });
  } catch (error) {
    logger.error('Error fetching user details', { error, userId: req.params.id, adminId: req.admin?.id });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to fetch user details',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * PATCH /v1/admin/users/:id
 * Update user information
 */
router.patch('/:id', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { email, emailVerified, status } = req.body;

    // Validate user exists
    const existingUser = await prisma.user.findUnique({ where: { id } });
    if (!existingUser) {
      res.status(404).json({
        error: true,
        code: 'USER_NOT_FOUND',
        message: 'User not found',
        timestamp: new Date().toISOString(),
      });
      return;
    }

    // Build update data
    const updateData: any = {};
    if (email !== undefined) {
      // Check if email is already taken
      const emailExists = await prisma.user.findFirst({
        where: {
          email,
          id: { not: id },
        },
      });

      if (emailExists) {
        res.status(400).json({
          error: true,
          code: 'EMAIL_TAKEN',
          message: 'Email address is already in use',
          timestamp: new Date().toISOString(),
        });
        return;
      }

      updateData.email = email;
    }

    if (emailVerified !== undefined) {
      updateData.email_verified = emailVerified;
    }

    if (status !== undefined) {
      if (!['active', 'suspended', 'deleted'].includes(status)) {
        res.status(400).json({
          error: true,
          code: 'INVALID_STATUS',
          message: 'Status must be one of: active, suspended, deleted',
          timestamp: new Date().toISOString(),
        });
        return;
      }
      updateData.status = status;
    }

    // Update user
    const updatedUser = await prisma.user.update({
      where: { id },
      data: updateData,
      include: {
        subscriptions: true,
      },
    });

    // Log admin action
    await prisma.auditLog.create({
      data: {
        action: 'admin.user.updated',
        resource_type: 'user',
        resource_id: id,
        ip_address: req.clientIp,
        user_agent: req.headers['user-agent'],
        details: {
          adminId: req.admin?.id,
          adminEmail: req.admin?.email,
          changes: updateData,
        },
      },
    });

    const updatedSubscription = updatedUser.subscriptions[0];
    res.json({
      id: updatedUser.id,
      email: updatedUser.email,
      emailVerified: updatedUser.email_verified,
      status: updatedUser.status,
      subscription: updatedSubscription
        ? {
            plan: updatedSubscription.plan_tier,
            status: updatedSubscription.status,
          }
        : null,
      updatedAt: updatedUser.updated_at.toISOString(),
    });
  } catch (error) {
    logger.error('Error updating user', { error, userId: req.params.id, adminId: req.admin?.id });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to update user',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * POST /v1/admin/users/:id/suspend
 * Suspend a user account
 */
router.post('/:id/suspend', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { reason } = req.body;

    const user = await prisma.user.findUnique({ where: { id } });
    if (!user) {
      res.status(404).json({
        error: true,
        code: 'USER_NOT_FOUND',
        message: 'User not found',
        timestamp: new Date().toISOString(),
      });
      return;
    }

    if (user.status === 'suspended') {
      res.status(400).json({
        error: true,
        code: 'ALREADY_SUSPENDED',
        message: 'User is already suspended',
        timestamp: new Date().toISOString(),
      });
      return;
    }

    // Update user status
    await prisma.user.update({
      where: { id },
      data: { status: 'suspended' },
    });

    // Log admin action
    await prisma.auditLog.create({
      data: {
        action: 'admin.user.suspended',
        resource_type: 'user',
        resource_id: id,
        ip_address: req.clientIp,
        user_agent: req.headers['user-agent'],
        details: {
          adminId: req.admin?.id,
          adminEmail: req.admin?.email,
          reason: reason || 'No reason provided',
        },
      },
    });

    res.json({
      success: true,
      message: 'User suspended successfully',
      userId: id,
      timestamp: new Date().toISOString(),
    });
  } catch (error) {
    logger.error('Error suspending user', { error, userId: req.params.id, adminId: req.admin?.id });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to suspend user',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * POST /v1/admin/users/:id/activate
 * Activate a suspended user account
 */
router.post('/:id/activate', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { id } = req.params;

    const user = await prisma.user.findUnique({ where: { id } });
    if (!user) {
      res.status(404).json({
        error: true,
        code: 'USER_NOT_FOUND',
        message: 'User not found',
        timestamp: new Date().toISOString(),
      });
      return;
    }

    if (user.status === 'active') {
      res.status(400).json({
        error: true,
        code: 'ALREADY_ACTIVE',
        message: 'User is already active',
        timestamp: new Date().toISOString(),
      });
      return;
    }

    if (user.status === 'deleted') {
      res.status(400).json({
        error: true,
        code: 'CANNOT_ACTIVATE_DELETED',
        message: 'Cannot activate a deleted user',
        timestamp: new Date().toISOString(),
      });
      return;
    }

    // Update user status
    await prisma.user.update({
      where: { id },
      data: { status: 'active' },
    });

    // Log admin action
    await prisma.auditLog.create({
      data: {
        action: 'admin.user.activated',
        resource_type: 'user',
        resource_id: id,
        ip_address: req.clientIp,
        user_agent: req.headers['user-agent'],
        details: {
          adminId: req.admin?.id,
          adminEmail: req.admin?.email,
        },
      },
    });

    res.json({
      success: true,
      message: 'User activated successfully',
      userId: id,
      timestamp: new Date().toISOString(),
    });
  } catch (error) {
    logger.error('Error activating user', { error, userId: req.params.id, adminId: req.admin?.id });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to activate user',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * POST /v1/admin/users/:id/reset-password
 * Send a password reset email to the user
 */
router.post('/:id/reset-password', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { id } = req.params;

    const user = await prisma.user.findUnique({ where: { id } });
    if (!user) {
      res.status(404).json({
        error: true,
        code: 'USER_NOT_FOUND',
        message: 'User not found',
        timestamp: new Date().toISOString(),
      });
      return;
    }

    // Generate reset token (1 hour expiry)
    const resetToken = generateToken();
    const resetExpires = new Date(Date.now() + 3600000);

    await prisma.user.update({
      where: { id },
      data: {
        password_reset_token: resetToken,
        password_reset_expires: resetExpires,
      },
    });

    // Send password reset email
    await sendPasswordResetEmail(user.email, resetToken);

    // Log admin action
    await prisma.auditLog.create({
      data: {
        action: 'admin.user.password_reset_sent',
        resource_type: 'user',
        resource_id: id,
        ip_address: req.clientIp,
        user_agent: req.headers['user-agent'],
        details: {
          adminId: req.admin?.id,
          adminEmail: req.admin?.email,
          userEmail: user.email,
        },
      },
    });

    logger.info('Admin triggered password reset', {
      adminId: req.admin?.id,
      userId: id,
      userEmail: user.email,
    });

    res.json({
      success: true,
      message: `Password reset email sent to ${user.email}`,
      timestamp: new Date().toISOString(),
    });
  } catch (error) {
    logger.error('Error sending password reset', { error, userId: req.params.id, adminId: req.admin?.id });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to send password reset email',
      timestamp: new Date().toISOString(),
    });
  }
});

/**
 * POST /v1/admin/users/:id/api-keys/revoke
 * Revoke all API keys for a user
 */
router.post('/:id/api-keys/revoke', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const { id } = req.params;

    const user = await prisma.user.findUnique({ where: { id } });
    if (!user) {
      res.status(404).json({
        error: true,
        code: 'USER_NOT_FOUND',
        message: 'User not found',
        timestamp: new Date().toISOString(),
      });
      return;
    }

    // Deactivate all API keys
    const result = await prisma.apiKey.updateMany({
      where: {
        user_id: id,
        is_active: true,
      },
      data: {
        is_active: false,
      },
    });

    // Log admin action
    await prisma.auditLog.create({
      data: {
        action: 'admin.api_keys.revoked',
        resource_type: 'user',
        resource_id: id,
        ip_address: req.clientIp,
        user_agent: req.headers['user-agent'],
        details: {
          adminId: req.admin?.id,
          adminEmail: req.admin?.email,
          keysRevoked: result.count,
        },
      },
    });

    res.json({
      success: true,
      message: `Revoked ${result.count} API key(s)`,
      keysRevoked: result.count,
      timestamp: new Date().toISOString(),
    });
  } catch (error) {
    logger.error('Error revoking API keys', { error, userId: req.params.id, adminId: req.admin?.id });
    res.status(500).json({
      error: true,
      code: 'INTERNAL_ERROR',
      message: 'Failed to revoke API keys',
      timestamp: new Date().toISOString(),
    });
  }
});

export default router;
