/**
 * @ai-summary Fastify route handlers for admin user management API
 * @ai-context HTTP request/response handling for managing all application users (not just admins)
 */

import { FastifyRequest, FastifyReply } from 'fastify';
import { UserProfileService } from '../../user-profile/domain/user-profile.service';
import { UserProfileRepository } from '../../user-profile/data/user-profile.repository';
import { AdminRepository } from '../data/admin.repository';
import { SubscriptionsService } from '../../subscriptions/domain/subscriptions.service';
import { SubscriptionsRepository } from '../../subscriptions/data/subscriptions.repository';
import { StripeClient } from '../../subscriptions/external/stripe/stripe.client';
import { pool } from '../../../core/config/database';
import { logger } from '../../../core/logging/logger';
import {
  listUsersQuerySchema,
  userAuth0SubSchema,
  updateTierSchema,
  deactivateUserSchema,
  updateProfileSchema,
  promoteToAdminSchema,
  ListUsersQueryInput,
  UserAuth0SubInput,
  UpdateTierInput,
  DeactivateUserInput,
  UpdateProfileInput,
  PromoteToAdminInput,
} from './users.validation';
import { AdminService } from '../domain/admin.service';

export class UsersController {
  private userProfileService: UserProfileService;
  private adminService: AdminService;
  private subscriptionsService: SubscriptionsService;
  private userProfileRepository: UserProfileRepository;
  private adminRepository: AdminRepository;

  constructor() {
    this.userProfileRepository = new UserProfileRepository(pool);
    this.adminRepository = new AdminRepository(pool);
    const subscriptionsRepository = new SubscriptionsRepository(pool);
    const stripeClient = new StripeClient();

    this.userProfileService = new UserProfileService(this.userProfileRepository);
    this.userProfileService.setAdminRepository(this.adminRepository);
    this.adminService = new AdminService(this.adminRepository);
    // Admin feature depends on Subscriptions for tier management
    // This is intentional - admin has oversight capabilities
    this.subscriptionsService = new SubscriptionsService(subscriptionsRepository, stripeClient, pool);
  }

  /**
   * GET /api/admin/stats - Get admin dashboard stats
   */
  async getAdminStats(
    request: FastifyRequest,
    reply: FastifyReply
  ) {
    try {
      const actorId = request.userContext?.userId;
      if (!actorId) {
        return reply.code(401).send({
          error: 'Unauthorized',
          message: 'User context missing',
        });
      }

      // Defense-in-depth: verify admin status even with requireAdmin guard
      if (!request.userContext?.isAdmin) {
        return reply.code(403).send({
          error: 'Forbidden',
          message: 'Admin access required',
        });
      }

      const [totalVehicles, totalUsers] = await Promise.all([
        this.userProfileRepository.getTotalVehicleCount(),
        this.userProfileRepository.getTotalUserCount(),
      ]);

      return reply.code(200).send({
        totalVehicles,
        totalUsers,
      });
    } catch (error) {
      logger.error('Error getting admin stats', {
        error: error instanceof Error ? error.message : 'Unknown error',
      });

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to get admin stats',
      });
    }
  }

  /**
   * GET /api/admin/users/:auth0Sub/vehicles - Get user's vehicles (admin view)
   */
  async getUserVehicles(
    request: FastifyRequest<{ Params: UserAuth0SubInput }>,
    reply: FastifyReply
  ) {
    try {
      const actorId = request.userContext?.userId;
      if (!actorId) {
        return reply.code(401).send({
          error: 'Unauthorized',
          message: 'User context missing',
        });
      }

      // Defense-in-depth: verify admin status even with requireAdmin guard
      if (!request.userContext?.isAdmin) {
        return reply.code(403).send({
          error: 'Forbidden',
          message: 'Admin access required',
        });
      }

      // Validate path param
      const parseResult = userAuth0SubSchema.safeParse(request.params);
      if (!parseResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: parseResult.error.errors.map(e => e.message).join(', '),
        });
      }

      const { auth0Sub } = parseResult.data;
      const vehicles = await this.userProfileRepository.getUserVehiclesForAdmin(auth0Sub);

      return reply.code(200).send({ vehicles });
    } catch (error) {
      logger.error('Error getting user vehicles', {
        error: error instanceof Error ? error.message : 'Unknown error',
        auth0Sub: request.params?.auth0Sub,
      });

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to get user vehicles',
      });
    }
  }

  /**
   * GET /api/admin/users - List all users with pagination and filters
   */
  async listUsers(
    request: FastifyRequest<{ Querystring: ListUsersQueryInput }>,
    reply: FastifyReply
  ) {
    try {
      const actorId = request.userContext?.userId;
      if (!actorId) {
        return reply.code(401).send({
          error: 'Unauthorized',
          message: 'User context missing',
        });
      }

      // Validate and parse query params
      const parseResult = listUsersQuerySchema.safeParse(request.query);
      if (!parseResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: parseResult.error.errors.map(e => e.message).join(', '),
        });
      }

      const query = parseResult.data;
      const result = await this.userProfileService.listAllUsers(query);

      return reply.code(200).send(result);
    } catch (error) {
      logger.error('Error listing users', {
        error: error instanceof Error ? error.message : 'Unknown error',
      });

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to list users',
      });
    }
  }

  /**
   * GET /api/admin/users/:auth0Sub - Get single user details
   */
  async getUser(
    request: FastifyRequest<{ Params: UserAuth0SubInput }>,
    reply: FastifyReply
  ) {
    try {
      const actorId = request.userContext?.userId;
      if (!actorId) {
        return reply.code(401).send({
          error: 'Unauthorized',
          message: 'User context missing',
        });
      }

      // Validate path param
      const parseResult = userAuth0SubSchema.safeParse(request.params);
      if (!parseResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: parseResult.error.errors.map(e => e.message).join(', '),
        });
      }

      const { auth0Sub } = parseResult.data;
      const user = await this.userProfileService.getUserDetails(auth0Sub);

      if (!user) {
        return reply.code(404).send({
          error: 'Not found',
          message: 'User not found',
        });
      }

      return reply.code(200).send(user);
    } catch (error) {
      logger.error('Error getting user details', {
        error: error instanceof Error ? error.message : 'Unknown error',
        auth0Sub: request.params?.auth0Sub,
      });

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to get user details',
      });
    }
  }

  /**
   * PATCH /api/admin/users/:auth0Sub/tier - Update subscription tier
   * Uses subscriptionsService.adminOverrideTier() to sync both subscriptions.tier
   * and user_profiles.subscription_tier atomically
   */
  async updateTier(
    request: FastifyRequest<{ Params: UserAuth0SubInput; Body: UpdateTierInput }>,
    reply: FastifyReply
  ) {
    try {
      const actorId = request.userContext?.userId;
      if (!actorId) {
        return reply.code(401).send({
          error: 'Unauthorized',
          message: 'User context missing',
        });
      }

      // Validate path param
      const paramsResult = userAuth0SubSchema.safeParse(request.params);
      if (!paramsResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: paramsResult.error.errors.map(e => e.message).join(', '),
        });
      }

      // Validate body
      const bodyResult = updateTierSchema.safeParse(request.body);
      if (!bodyResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: bodyResult.error.errors.map(e => e.message).join(', '),
        });
      }

      const { auth0Sub } = paramsResult.data;
      const { subscriptionTier } = bodyResult.data;

      // Verify user exists before attempting tier change
      const currentUser = await this.userProfileService.getUserDetails(auth0Sub);
      if (!currentUser) {
        return reply.code(404).send({
          error: 'Not found',
          message: 'User not found',
        });
      }

      const previousTier = currentUser.subscriptionTier;

      // Use subscriptionsService to update both tables atomically
      await this.subscriptionsService.adminOverrideTier(auth0Sub, subscriptionTier);

      // Log audit action
      await this.adminRepository.logAuditAction(
        actorId,
        'UPDATE_TIER',
        auth0Sub,
        'user_profile',
        currentUser.id,
        { previousTier, newTier: subscriptionTier }
      );

      logger.info('User subscription tier updated via admin', {
        auth0Sub,
        previousTier,
        newTier: subscriptionTier,
        actorAuth0Sub: actorId,
      });

      // Return updated user profile
      const updatedUser = await this.userProfileService.getUserDetails(auth0Sub);
      return reply.code(200).send(updatedUser);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';

      logger.error('Error updating user tier', {
        error: errorMessage,
        auth0Sub: request.params?.auth0Sub,
      });

      if (errorMessage === 'User not found') {
        return reply.code(404).send({
          error: 'Not found',
          message: errorMessage,
        });
      }

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to update subscription tier',
      });
    }
  }

  /**
   * PATCH /api/admin/users/:auth0Sub/deactivate - Soft delete user
   */
  async deactivateUser(
    request: FastifyRequest<{ Params: UserAuth0SubInput; Body: DeactivateUserInput }>,
    reply: FastifyReply
  ) {
    try {
      const actorId = request.userContext?.userId;
      if (!actorId) {
        return reply.code(401).send({
          error: 'Unauthorized',
          message: 'User context missing',
        });
      }

      // Validate path param
      const paramsResult = userAuth0SubSchema.safeParse(request.params);
      if (!paramsResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: paramsResult.error.errors.map(e => e.message).join(', '),
        });
      }

      // Validate body (optional)
      const bodyResult = deactivateUserSchema.safeParse(request.body || {});
      if (!bodyResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: bodyResult.error.errors.map(e => e.message).join(', '),
        });
      }

      const { auth0Sub } = paramsResult.data;
      const { reason } = bodyResult.data;

      const deactivatedUser = await this.userProfileService.deactivateUser(
        auth0Sub,
        actorId,
        reason
      );

      return reply.code(200).send(deactivatedUser);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';

      logger.error('Error deactivating user', {
        error: errorMessage,
        auth0Sub: request.params?.auth0Sub,
      });

      if (errorMessage === 'User not found') {
        return reply.code(404).send({
          error: 'Not found',
          message: errorMessage,
        });
      }

      if (errorMessage === 'Cannot deactivate your own account') {
        return reply.code(400).send({
          error: 'Bad request',
          message: errorMessage,
        });
      }

      if (errorMessage === 'User is already deactivated') {
        return reply.code(400).send({
          error: 'Bad request',
          message: errorMessage,
        });
      }

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to deactivate user',
      });
    }
  }

  /**
   * PATCH /api/admin/users/:auth0Sub/reactivate - Restore deactivated user
   */
  async reactivateUser(
    request: FastifyRequest<{ Params: UserAuth0SubInput }>,
    reply: FastifyReply
  ) {
    try {
      const actorId = request.userContext?.userId;
      if (!actorId) {
        return reply.code(401).send({
          error: 'Unauthorized',
          message: 'User context missing',
        });
      }

      // Validate path param
      const paramsResult = userAuth0SubSchema.safeParse(request.params);
      if (!paramsResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: paramsResult.error.errors.map(e => e.message).join(', '),
        });
      }

      const { auth0Sub } = paramsResult.data;

      const reactivatedUser = await this.userProfileService.reactivateUser(
        auth0Sub,
        actorId
      );

      return reply.code(200).send(reactivatedUser);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';

      logger.error('Error reactivating user', {
        error: errorMessage,
        auth0Sub: request.params?.auth0Sub,
      });

      if (errorMessage === 'User not found') {
        return reply.code(404).send({
          error: 'Not found',
          message: errorMessage,
        });
      }

      if (errorMessage === 'User is not deactivated') {
        return reply.code(400).send({
          error: 'Bad request',
          message: errorMessage,
        });
      }

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to reactivate user',
      });
    }
  }

  /**
   * PATCH /api/admin/users/:auth0Sub/profile - Update user email/displayName
   */
  async updateProfile(
    request: FastifyRequest<{ Params: UserAuth0SubInput; Body: UpdateProfileInput }>,
    reply: FastifyReply
  ) {
    try {
      const actorId = request.userContext?.userId;
      if (!actorId) {
        return reply.code(401).send({
          error: 'Unauthorized',
          message: 'User context missing',
        });
      }

      // Validate path param
      const paramsResult = userAuth0SubSchema.safeParse(request.params);
      if (!paramsResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: paramsResult.error.errors.map(e => e.message).join(', '),
        });
      }

      // Validate body
      const bodyResult = updateProfileSchema.safeParse(request.body);
      if (!bodyResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: bodyResult.error.errors.map(e => e.message).join(', '),
        });
      }

      const { auth0Sub } = paramsResult.data;
      const updates = bodyResult.data;

      const updatedUser = await this.userProfileService.adminUpdateProfile(
        auth0Sub,
        updates,
        actorId
      );

      return reply.code(200).send(updatedUser);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';

      logger.error('Error updating user profile', {
        error: errorMessage,
        auth0Sub: request.params?.auth0Sub,
      });

      if (errorMessage === 'User not found') {
        return reply.code(404).send({
          error: 'Not found',
          message: errorMessage,
        });
      }

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to update user profile',
      });
    }
  }

  /**
   * PATCH /api/admin/users/:auth0Sub/promote - Promote user to admin
   */
  async promoteToAdmin(
    request: FastifyRequest<{ Params: UserAuth0SubInput; Body: PromoteToAdminInput }>,
    reply: FastifyReply
  ) {
    try {
      const actorId = request.userContext?.userId;
      if (!actorId) {
        return reply.code(401).send({
          error: 'Unauthorized',
          message: 'User context missing',
        });
      }

      // Validate path param
      const paramsResult = userAuth0SubSchema.safeParse(request.params);
      if (!paramsResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: paramsResult.error.errors.map(e => e.message).join(', '),
        });
      }

      // Validate body
      const bodyResult = promoteToAdminSchema.safeParse(request.body || {});
      if (!bodyResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: bodyResult.error.errors.map(e => e.message).join(', '),
        });
      }

      const { auth0Sub } = paramsResult.data;
      const { role } = bodyResult.data;

      // Get the user profile first to verify they exist and get their email
      const user = await this.userProfileService.getUserDetails(auth0Sub);
      if (!user) {
        return reply.code(404).send({
          error: 'Not found',
          message: 'User not found',
        });
      }

      // Check if user is already an admin
      if (user.isAdmin) {
        return reply.code(400).send({
          error: 'Bad request',
          message: 'User is already an admin',
        });
      }

      // Create the admin record using the user's real auth0Sub
      const adminUser = await this.adminService.createAdmin(
        user.email,
        role,
        auth0Sub, // Use the real auth0Sub from the user profile
        actorId
      );

      return reply.code(201).send(adminUser);
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';

      logger.error('Error promoting user to admin', {
        error: errorMessage,
        auth0Sub: request.params?.auth0Sub,
      });

      if (errorMessage.includes('already exists')) {
        return reply.code(400).send({
          error: 'Bad request',
          message: errorMessage,
        });
      }

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to promote user to admin',
      });
    }
  }

  /**
   * DELETE /api/admin/users/:auth0Sub - Hard delete user (permanent)
   */
  async hardDeleteUser(
    request: FastifyRequest<{ Params: UserAuth0SubInput }>,
    reply: FastifyReply
  ) {
    try {
      const actorId = request.userContext?.userId;
      if (!actorId) {
        return reply.code(401).send({
          error: 'Unauthorized',
          message: 'User context missing',
        });
      }

      // Validate path param
      const paramsResult = userAuth0SubSchema.safeParse(request.params);
      if (!paramsResult.success) {
        return reply.code(400).send({
          error: 'Validation error',
          message: paramsResult.error.errors.map(e => e.message).join(', '),
        });
      }

      const { auth0Sub } = paramsResult.data;

      // Optional reason from query params
      const reason = (request.query as any)?.reason;

      // Hard delete user
      await this.userProfileService.adminHardDeleteUser(
        auth0Sub,
        actorId,
        reason
      );

      return reply.code(200).send({
        message: 'User permanently deleted',
      });
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Unknown error';

      logger.error('Error hard deleting user', {
        error: errorMessage,
        auth0Sub: request.params?.auth0Sub,
      });

      if (errorMessage === 'Cannot delete your own account') {
        return reply.code(400).send({
          error: 'Bad request',
          message: errorMessage,
        });
      }

      if (errorMessage === 'User not found') {
        return reply.code(404).send({
          error: 'Not found',
          message: errorMessage,
        });
      }

      return reply.code(500).send({
        error: 'Internal server error',
        message: 'Failed to delete user',
      });
    }
  }
}
