/**
 * Users Service
 * Mecánicas Diesel - ERP Suite
 */

import { Repository, DataSource } from 'typeorm';
import bcrypt from 'bcryptjs';
import { User, UserRole } from '../auth/entities/user.entity';
import {
  CreateUserDto,
  UpdateUserDto,
  ResetPasswordDto,
  UserFilters,
  PaginationOptions,
  PaginatedResult,
} from './users.dto';

export class UsersService {
  private userRepository: Repository<User>;

  constructor(dataSource: DataSource) {
    this.userRepository = dataSource.getRepository(User);
  }

  /**
   * Create a new user
   */
  async create(tenantId: string, dto: CreateUserDto): Promise<Omit<User, 'passwordHash'>> {
    // Check if email already exists
    const existing = await this.userRepository.findOne({
      where: { email: dto.email },
    });

    if (existing) {
      throw new Error('El email ya está registrado');
    }

    const passwordHash = await bcrypt.hash(dto.password, 10);

    const user = this.userRepository.create({
      tenantId,
      email: dto.email,
      passwordHash,
      fullName: dto.fullName,
      role: dto.role,
      avatarUrl: dto.avatarUrl,
      isActive: true,
      emailVerified: false,
    });

    const savedUser = await this.userRepository.save(user);
    return savedUser.toJSON() as Omit<User, 'passwordHash'>;
  }

  /**
   * Find user by ID
   */
  async findById(tenantId: string, id: string): Promise<Omit<User, 'passwordHash'> | null> {
    const user = await this.userRepository.findOne({
      where: { id, tenantId },
    });

    if (!user) return null;
    return user.toJSON() as Omit<User, 'passwordHash'>;
  }

  /**
   * List users with filters and pagination
   */
  async findAll(
    tenantId: string,
    filters: UserFilters = {},
    pagination: PaginationOptions = { page: 1, limit: 20 }
  ): Promise<PaginatedResult<Omit<User, 'passwordHash'>>> {
    const queryBuilder = this.userRepository
      .createQueryBuilder('user')
      .where('user.tenant_id = :tenantId', { tenantId });

    // Apply filters
    if (filters.role) {
      queryBuilder.andWhere('user.role = :role', { role: filters.role });
    }

    if (filters.isActive !== undefined) {
      queryBuilder.andWhere('user.is_active = :isActive', { isActive: filters.isActive });
    }

    if (filters.search) {
      queryBuilder.andWhere(
        '(user.full_name ILIKE :search OR user.email ILIKE :search)',
        { search: `%${filters.search}%` }
      );
    }

    // Apply pagination
    const skip = (pagination.page - 1) * pagination.limit;
    queryBuilder
      .orderBy('user.created_at', 'DESC')
      .skip(skip)
      .take(pagination.limit);

    const [users, total] = await queryBuilder.getManyAndCount();

    return {
      data: users.map((user) => user.toJSON() as Omit<User, 'passwordHash'>),
      total,
      page: pagination.page,
      limit: pagination.limit,
      totalPages: Math.ceil(total / pagination.limit),
    };
  }

  /**
   * Update user
   */
  async update(
    tenantId: string,
    id: string,
    dto: UpdateUserDto
  ): Promise<Omit<User, 'passwordHash'> | null> {
    const user = await this.userRepository.findOne({
      where: { id, tenantId },
    });

    if (!user) return null;

    if (dto.fullName !== undefined) user.fullName = dto.fullName;
    if (dto.role !== undefined) user.role = dto.role;
    if (dto.isActive !== undefined) user.isActive = dto.isActive;
    if (dto.avatarUrl !== undefined) user.avatarUrl = dto.avatarUrl || undefined;

    const savedUser = await this.userRepository.save(user);
    return savedUser.toJSON() as Omit<User, 'passwordHash'>;
  }

  /**
   * Soft delete user (deactivate)
   */
  async delete(tenantId: string, id: string): Promise<boolean> {
    const user = await this.userRepository.findOne({
      where: { id, tenantId },
    });

    if (!user) return false;

    user.isActive = false;
    await this.userRepository.save(user);
    return true;
  }

  /**
   * Reset user password (admin only)
   */
  async resetPassword(
    tenantId: string,
    id: string,
    dto: ResetPasswordDto
  ): Promise<boolean> {
    const user = await this.userRepository.findOne({
      where: { id, tenantId },
    });

    if (!user) return false;

    user.passwordHash = await bcrypt.hash(dto.newPassword, 10);
    await this.userRepository.save(user);
    return true;
  }
}
