import { Body, Controller, Get, HttpException, HttpStatus, Inject, Param, Post, Query, Req, UseGuards } from '@nestjs/common';
import * as admin from 'firebase-admin';
import { AdminGuard } from 'src/jwt-auth/admin-auth.guard';
import { AuthGuard } from 'src/jwt-auth/auth.guard';
import { LocalhostGuard } from 'src/jwt-auth/localhost.guard';
import { UserRole, UsersResponse } from 'src/models/main.model';
import { AuthService } from './auth.service';

@Controller('auth')
export class AuthController {
  constructor(
    @Inject('FIREBASE_ADMIN')
    private readonly firebaseAdmin: typeof admin,
    private readonly authService: AuthService,
  ) {}
  @Post('verify-email')
  async verifyEmail(@Body('oobCode') oobCode: string, @Body('email') email: string) {
    if (!oobCode || !email) {
      throw new HttpException('oobCode and email are required', HttpStatus.BAD_REQUEST);
    }

    try {
      // Step 1: Get the user by email address
      const userRecord = await this.firebaseAdmin.auth().getUserByEmail(email);

      if (userRecord.emailVerified) {
        // Even if already verified, we'll still return a valid token
        const customToken = await this.firebaseAdmin.auth().createCustomToken(userRecord.uid);
        return {
          message: 'Email is already verified',
          token: customToken,
        };
      }

      // Step 2: Update the user status to set emailVerified to true
      await this.firebaseAdmin.auth().updateUser(userRecord.uid, {
        emailVerified: true,
      });

      // Step 3: Generate a custom Firebase token for the user
      // This token can be used on the client side to authenticate with Firebase
      const customToken = await this.firebaseAdmin.auth().createCustomToken(userRecord.uid);

      return {
        message: 'Email successfully verified',
        token: customToken,
      };
    } catch (error) {
      throw new HttpException(error.message || 'Failed to verify email', HttpStatus.BAD_REQUEST);
    }
  }
  @Post(':uid/role')
  @UseGuards(AuthGuard, AdminGuard) // Only admins can change roles
  async setUserRole(@Param('uid') uid: string, @Body('role') role: UserRole): Promise<{ success: boolean }> {
    await this.authService.setUserRole(uid, role);
    return { success: true };
  }

  @Get('me/role')
  @UseGuards(AuthGuard)
  async getMyRole(@Req() req: any): Promise<{ role: UserRole | null }> {
    console.log('->', req.user);
    console.log('-->', req.user.uid);
    const uid = req.user.uid; // From FirebaseAuthGuard
    const role = await this.authService.getUserRole(uid);
    return { role };
  }

  @Get(':uid/role')
  @UseGuards(AuthGuard)
  async getUserRole(@Param('uid') uid: string): Promise<{ role: UserRole | null }> {
    const role = await this.authService.getUserRole(uid);
    return { role };
  }

  @Get('role/:role')
  @UseGuards(AuthGuard, AdminGuard) // Only admins can list users by role
  async getUsersByRole(@Param('role') role: UserRole): Promise<{ users: any[] }> {
    const users = await this.authService.getUsersByRole(role);
    // Map to simpler objects to avoid circular references
    const simplifiedUsers = users.map(user => ({
      uid: user.uid,
      email: user.email,
      displayName: user.displayName,
    }));
    return { users: simplifiedUsers };
  }

  /**
   * Ruft alle Firebase-Benutzer mit ihren Rollen ab
   * @param maxResults Maximale Anzahl an zurückzugebenden Benutzern (optional, Standard: 1000)
   * @param pageToken Token für die Paginierung (optional)
   * @returns Eine Liste von Benutzern mit ihren Rollen und Metadaten
   */
  @Get()
  @UseGuards(AuthGuard, AdminGuard) // Only admins can list all users
  async getAllUsers(@Query('maxResults') maxResults?: number, @Query('pageToken') pageToken?: string): Promise<UsersResponse> {
    const result = await this.authService.getAllUsers(maxResults ? parseInt(maxResults.toString(), 10) : undefined, pageToken);

    return {
      users: result.users,
      totalCount: result.users.length,
      ...(result.pageToken && { pageToken: result.pageToken }),
    };
  }

  /**
   * Endpoint zum direkten Einstellen einer Rolle für Debug-Zwecke
   * WARNUNG: Dieser Endpoint sollte in der Produktion entfernt oder stark gesichert werden
   */
  @Post('set-role')
  @UseGuards(AuthGuard, LocalhostGuard)
  async setUserRoleOnLocalhost(@Req() req: any, @Body('role') role: UserRole): Promise<{ success: boolean; message: string }> {
    try {
      const uid = req.user.uid;

      // Aktuelle Rolle protokollieren
      const currentUser = await this.authService.getUserRole(uid);
      console.log(`Changing role for user ${uid} from ${currentUser} to ${role}`);

      // Neue Rolle setzen
      await this.authService.setUserRole(uid, role);

      // Rolle erneut prüfen, um zu bestätigen
      const newRole = await this.authService.getUserRole(uid);

      return {
        success: true,
        message: `Rolle für Benutzer ${uid} von ${currentUser} zu ${newRole} geändert`,
      };
    } catch (error) {
      console.error('Fehler beim Setzen der Rolle:', error);
      return {
        success: false,
        message: `Fehler: ${error.message}`,
      };
    }
  }
}
