/**
 * User Management Service
 *
 * Centralized business logic for user management operations.
 * Handles user queries, account status changes, and analytics calculations.
 *
 * @module services/user-management
 */

import { prisma } from '@/lib/db';
import type {
  User,
  UserListQuery,
  UserListResponse,
  UserDetailsResponse,
  AccountStatusUpdate,
  UserAnalytics,
} from '@/lib/types/user-management.types';

/**
 * User Management Service Class
 *
 * Provides methods for all user management operations including:
 * - Listing users with filters and pagination
 * - Fetching user details and analytics
 * - Account suspension and activation
 * - Login history tracking
 */
export class UserManagementService {
  /**
   * List users with advanced filtering and analytics
   *
   * @param query - Filter and pagination parameters
   * @returns Paginated user list with analytics
   *
   * @example
   * const result = await service.listUsers({
   *   status: 'active',
   *   country: 'Qatar',
   *   page: 1,
   *   limit: 50
   * });
   */
  async listUsers(query: UserListQuery): Promise<UserListResponse> {
    const {
      search,
      status = 'all',
      role,
      country,
      page = 1,
      limit = 50,
      sortBy = 'createdAt',
      sortOrder = 'desc',
    } = query;

    // Build where clause
    const where = this.buildUserWhereClause({
      search,
      status,
      role,
      country,
    });

    // Calculate pagination
    const skip = (page - 1) * limit;
    const orderBy = { [sortBy]: sortOrder };

    // Fetch users and total count in parallel
    const [users, totalCount] = await Promise.all([
      prisma.users.findMany({
        where,
        orderBy,
        skip,
        take: limit,
        select: this.getUserSelectFields(),
      }),
      prisma.users.count({ where }),
    ]);

    // Calculate analytics
    const analytics = await this.calculateUserAnalytics(where);

    // Map users with computed fields
    const enhancedUsers = users.map((user) => ({
      ...user,
      accountStatus: this.determineAccountStatus(user),
      hasSubscription: user._count.subscriptions > 0,
    }));

    return {
      users: enhancedUsers,
      analytics,
      pagination: {
        page,
        limit,
        total: totalCount,
        totalPages: Math.ceil(totalCount / limit),
        hasMore: skip + users.length < totalCount,
      },
    };
  }

  /**
   * Get comprehensive user details including history and analytics
   *
   * @param userId - User ID
   * @returns Complete user information
   *
   * @example
   * const details = await service.getUserDetails('user-123');
   */
  async getUserDetails(userId: string): Promise<UserDetailsResponse> {
    const user = await prisma.users.findUnique({
      where: { id: userId },
      include: {
        subscriptions: {
          orderBy: { createdAt: 'desc' },
          take: 10,
        },
        adminNotes: {
          orderBy: { createdAt: 'desc' },
          take: 50,
        },
        billingEmails: {
          orderBy: { sentAt: 'desc' },
          take: 50,
        },
        loginHistory: {
          orderBy: { createdAt: 'desc' },
          take: 50,
        },
        auditLogs: {
          orderBy: { createdAt: 'desc' },
          take: 50,
        },
        _count: {
          select: {
            subscriptions: true,
            adminNotes: true,
            billingEmails: true,
            loginHistory: true,
            auditLogs: true,
          },
        },
      },
    });

    if (!user) {
      throw new Error('User not found');
    }

    // Calculate login analytics
    const analytics = this.calculateLoginAnalytics(user.loginHistory);

    // Remove sensitive data
    const { password, ...safeUser } = user;

    return {
      user: safeUser,
      analytics,
    };
  }

  /**
   * Update user account status (suspend or activate)
   *
   * @param userId - User ID
   * @param update - Status update details
   * @param staffId - ID of staff member performing action
   * @returns Updated user data
   *
   * @example
   * await service.updateAccountStatus('user-123', {
   *   action: 'suspend',
   *   reason: 'Payment overdue'
   * }, 'staff-456');
   */
  async updateAccountStatus(
    userId: string,
    update: AccountStatusUpdate,
    staffId: string,
    ipAddress: string
  ) {
    const { action, reason } = update;

    // Validate action
    if (!['suspend', 'activate'].includes(action)) {
      throw new Error('Invalid action. Must be "suspend" or "activate"');
    }

    // Get current user
    const user = await prisma.users.findUnique({
      where: { id: userId },
      select: {
        id: true,
        email: true,
        name: true,
        role: true,
        isActive: true,
        isSuspended: true,
      },
    });

    if (!user) {
      throw new Error('User not found');
    }

    // Safety check: prevent admin suspension
    if ((user.role === 'ADMIN' || user.role === 'SUPER_ADMIN') && action === 'suspend') {
      throw new Error('Cannot suspend administrator accounts');
    }

    const isSuspending = action === 'suspend';

    // Update in Prisma
    const updated = await prisma.users.update({
      where: { id: userId },
      data: {
        isSuspended: isSuspending,
        isActive: !isSuspending,
        suspendedAt: isSuspending ? new Date() : null,
        suspendedBy: isSuspending ? staffId : null,
        suspendedReason: isSuspending ? reason : null,
        updatedAt: new Date(),
      },
    });

    // Create audit log

    // Remove password from response
    const { password, ...safeUser } = updated;
    return safeUser;
  }

  // ============================================
  // PRIVATE HELPER METHODS
  // ============================================

  /**
   * Build Prisma where clause from query filters
   * @private
   */
  private buildUserWhereClause(filters: {
    search?: string;
    status?: string;
    role?: string;
    country?: string;
  }) {
    const where: any = {
      role: filters.role || { in: ['CUSTOMER', 'STAFF', 'ADMIN'] },
    };

    // Status filtering
    if (filters.status === 'active') {
      where.isActive = true;
      where.isSuspended = false;
      where.lockedUntil = null;
    } else if (filters.status === 'suspended') {
      where.isSuspended = true;
    } else if (filters.status === 'locked') {
      where.lockedUntil = { gt: new Date() };
    }

    // Country filtering
    if (filters.country) {
      where.lastLoginCountry = filters.country;
    }

    // Search filtering
    if (filters.search) {
      where.OR = [
        { name: { contains: filters.search, mode: 'insensitive' } },
        { email: { contains: filters.search, mode: 'insensitive' } },
        { companyName: { contains: filters.search, mode: 'insensitive' } },
        { phoneNumber: { contains: filters.search, mode: 'insensitive' } },
      ];
    }

    return where;
  }

  /**
   * Get select fields for user queries
   * @private
   */
  private getUserSelectFields() {
    return {
      id: true,
      name: true,
      email: true,
      role: true,
      country: true,
      companyName: true,
      industry: true,
      selectedPackage: true,
      createdAt: true,
      lastLoginAt: true,
      lastLoginIp: true,
      lastLoginCountry: true,
      lastLoginCity: true,
      loginCount: true,
      isActive: true,
      isSuspended: true,
      suspendedAt: true,
      suspendedReason: true,
      lockedUntil: true,
      emailVerified: true,
      phoneNumber: true,
      _count: {
        select: {
          adminNotes: true,
          billingEmails: true,
          subscriptions: true,
          loginHistory: true,
        },
      },
    };
  }

  /**
   * Calculate comprehensive user analytics
   * @private
   */
  private async calculateUserAnalytics(where: any): Promise<UserAnalytics> {
    const oneWeekAgo = new Date();
    oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);

    const [total, active, suspended, locked, newThisWeek, activeSubscriptions] =
      await Promise.all([
        prisma.users.count({ where: { ...where, role: { in: ['CUSTOMER', 'STAFF', 'ADMIN'] } } }),
        prisma.users.count({
          where: { ...where, isActive: true, isSuspended: false },
        }),
        prisma.users.count({ where: { ...where, isSuspended: true } }),
        prisma.users.count({ where: { ...where, lockedUntil: { gt: new Date() } } }),
        prisma.users.count({
          where: { ...where, createdAt: { gte: oneWeekAgo } },
        }),
        prisma.subscriptions.count({
          where: { status: { in: ['active', 'trialing'] } },
        }),
      ]);

    return {
      total,
      active,
      suspended,
      locked,
      newThisWeek,
      activeSubscriptions,
      byCountry: {},
      byIndustry: {},
      byPackage: {},
    };
  }

  /**
   * Calculate login analytics from history records
   * @private
   */
  private calculateLoginAnalytics(loginHistory: any[]) {
    const uniqueIPs = new Set(loginHistory.map((l) => l.ipAddress));
    const uniqueCountries = new Set(
      loginHistory.map((l) => l.country).filter(Boolean)
    );
    const successful = loginHistory.filter((l) => l.success).length;
    const failed = loginHistory.filter((l) => !l.success).length;
    const successRate = loginHistory.length > 0 ? (successful / loginHistory.length) * 100 : 0;

    const recentCountries = [
      ...new Set(
        loginHistory
          .slice(0, 10)
          .map((l) => l.country)
          .filter(Boolean)
      ),
    ];

    return {
      loginStats: {
        total: loginHistory.length,
        successful,
        failed,
        successRate: Math.round(successRate * 100) / 100,
        uniqueIps: uniqueIPs.size,
        uniqueCountries: uniqueCountries.size,
        recentCountries,
      },
    };
  }

  /**
   * Determine account status from user flags
   * @private
   */
  private determineAccountStatus(user: {
    isActive: boolean;
    isSuspended: boolean;
    lockedUntil: Date | null;
  }): 'active' | 'suspended' | 'locked' | 'inactive' {
    if (user.isSuspended) return 'suspended';
    if (user.lockedUntil && new Date(user.lockedUntil) > new Date()) return 'locked';
    if (user.isActive) return 'active';
    return 'inactive';
  }

}

// Export singleton instance
export const userManagementService = new UserManagementService();
