import { logger } from '@goodgo/logger';
import { PrismaClient } from '@prisma/client';
import { Request } from 'express';

import { getPrismaClient } from '../../../config/database.config';
import { auditService } from '../../../core/events/audit.service';
import { NotFoundError, ConflictError } from '../../../errors/http-error';
import { UserProfileRepository } from '../../../repositories/user-profile.repository';
import { UserRepository } from '../../../repositories/user.repository';
import { getErrorMessage } from '../../../utils/error-utils';
import { UpdateUserDto, UserFiltersDto, BulkImportUsersDto } from '../identity.dto';

/**
 * EN: User Management Service for user lifecycle operations
 * VI: Service quản lý người dùng cho các thao tác vòng đời user
 */
export class UserManagementService {
  private prisma: PrismaClient;
  private userRepo: UserRepository;
  private profileRepo: UserProfileRepository;

  constructor() {
    this.prisma = getPrismaClient();
    this.userRepo = new UserRepository(this.prisma);
    this.profileRepo = new UserProfileRepository(this.prisma);
  }

  /**
   * EN: Get user by ID
   * VI: Lấy user theo ID
   */
  async getUser(userId: string): Promise<any> {
    const user = await this.userRepo.findWithPermissions(userId);
    if (!user) {
      throw new NotFoundError('User');
    }

    const profile = await this.profileRepo.findByUserId(userId);

    return {
      ...user,
      profile,
    };
  }

  /**
   * EN: Update user
   * VI: Cập nhật user
   */
  async updateUser(userId: string, data: UpdateUserDto, req?: Request): Promise<any> {
    const user = await this.userRepo.findById(userId);
    if (!user) {
      throw new NotFoundError('User');
    }

    // Check if email already exists for another user
    if (data.email && data.email !== user.email) {
      const existing = await this.userRepo.findByEmail(data.email);
      if (existing) {
        throw new ConflictError('Email already exists / Email đã tồn tại');
      }
    }

    // Check if username already exists for another user
    if (data.username && data.username !== user.username) {
      const existing = await this.userRepo.findByUsername(data.username);
      if (existing) {
        throw new ConflictError('Username already exists / Username đã tồn tại');
      }
    }

    const updated = await this.userRepo.update(userId, {
      ...(data.email && { email: data.email }),
      ...(data.username !== undefined && { username: data.username }),
      ...(data.isActive !== undefined && { isActive: data.isActive }),
      ...(data.organizationId !== undefined && { organizationId: data.organizationId }),
    });

    if (req) {
      await auditService.logFromRequest(req, 'USER_UPDATED', {
        userId: updated.id,
        changes: data,
        success: true,
      });
    }

    logger.info('User updated', { userId: updated.id });

    return updated;
  }

  /**
   * EN: Deactivate user (soft delete)
   * VI: Vô hiệu hóa user (soft delete)
   */
  async deactivateUser(userId: string, req?: Request): Promise<any> {
    const user = await this.userRepo.findById(userId);
    if (!user) {
      throw new NotFoundError('User');
    }

    const updated = await this.userRepo.update(userId, { isActive: false });

    // Revoke all active sessions
    await this.prisma.session.updateMany({
      where: { userId, isActive: true },
      data: { isActive: false },
    });

    if (req) {
      await auditService.logFromRequest(req, 'USER_DEACTIVATED', {
        userId: updated.id,
        success: true,
      });
    }

    logger.info('User deactivated', { userId: updated.id });

    return updated;
  }

  /**
   * EN: Reactivate user
   * VI: Kích hoạt lại user
   */
  async reactivateUser(userId: string, req?: Request): Promise<any> {
    const user = await this.userRepo.findById(userId);
    if (!user) {
      throw new NotFoundError('User');
    }

    const updated = await this.userRepo.update(userId, { isActive: true });

    if (req) {
      await auditService.logFromRequest(req, 'USER_REACTIVATED', {
        userId: updated.id,
        success: true,
      });
    }

    logger.info('User reactivated', { userId: updated.id });

    return updated;
  }

  /**
   * EN: Delete user (soft delete by deactivating)
   * VI: Xóa user (soft delete bằng cách vô hiệu hóa)
   */
  async deleteUser(userId: string, req?: Request): Promise<boolean> {
    await this.deactivateUser(userId, req);
    return true;
  }

  /**
   * EN: Search users with filters
   * VI: Tìm kiếm users với filters
   */
  async searchUsers(filters: UserFiltersDto): Promise<{ users: any[]; total: number }> {
    const where: any = {};

    if (filters.organizationId) {
      where.organizationId = filters.organizationId;
    }

    if (filters.isActive !== undefined) {
      where.isActive = filters.isActive;
    }

    if (filters.emailVerified !== undefined) {
      where.emailVerified = filters.emailVerified;
    }

    if (filters.search) {
      where.OR = [
        { email: { contains: filters.search, mode: 'insensitive' } },
        { username: { contains: filters.search, mode: 'insensitive' } },
      ];
    }

    const [users, total] = await Promise.all([
      this.prisma.user.findMany({
        where,
        skip: filters.skip,
        take: filters.take,
        orderBy: { createdAt: 'desc' },
        include: {
          profile: true,
          organization: {
            select: {
              id: true,
              name: true,
              domain: true,
            },
          },
        },
      }),
      this.prisma.user.count({ where }),
    ]);

    return { users, total };
  }

  /**
   * EN: Bulk import users
   * VI: Import hàng loạt users
   */
  async bulkImportUsers(data: BulkImportUsersDto, req?: Request): Promise<{ created: number; errors: any[] }> {
    const errors: any[] = [];
    let created = 0;

    for (const userData of data.users) {
      try {
        // Check if user exists
        const existing = await this.userRepo.findByEmail(userData.email);
        if (existing) {
          errors.push({ email: userData.email, error: 'User already exists' });
          continue;
        }

        // Create user
        const user = await this.prisma.user.create({
          data: {
            email: userData.email,
            username: userData.username || userData.email.split('@')[0],
            isActive: true,
            emailVerified: false,
            organizationId: data.organizationId || undefined,
          },
        });

        // Create profile if profile data provided
        if (userData.firstName || userData.lastName || userData.phone) {
          await this.profileRepo.upsert(user.id, {
            firstName: userData.firstName,
            lastName: userData.lastName,
            phone: userData.phone,
          });
        }

        created++;

        if (req) {
          await auditService.logFromRequest(req, 'USER_IMPORTED', {
            userId: user.id,
            email: user.email,
            success: true,
          });
        }
      } catch (error: unknown) {
        errors.push({ email: userData.email, error: getErrorMessage(error) });
      }
    }

    logger.info('Bulk import completed', { created, errors: errors.length });

    return { created, errors };
  }

  /**
   * EN: Bulk export users
   * VI: Export hàng loạt users
   */
  async bulkExportUsers(filters: UserFiltersDto): Promise<any[]> {
    const where: any = {};

    if (filters.organizationId) {
      where.organizationId = filters.organizationId;
    }

    if (filters.isActive !== undefined) {
      where.isActive = filters.isActive;
    }

    const users = await this.prisma.user.findMany({
      where,
      include: {
        profile: true,
        organization: {
          select: {
            id: true,
            name: true,
            domain: true,
          },
        },
      },
      orderBy: { createdAt: 'desc' },
    });

    return users.map((user) => ({
      id: user.id,
      email: user.email,
      username: user.username,
      isActive: user.isActive,
      emailVerified: user.emailVerified,
      firstName: user.profile?.firstName,
      lastName: user.profile?.lastName,
      phone: user.profile?.phone,
      organization: user.organization?.name,
      createdAt: user.createdAt,
      updatedAt: user.updatedAt,
    }));
  }
}

export const userManagementService = new UserManagementService();
