import { Injectable, inject } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { environment } from '@environments/environment';
import { Observable, map, catchError, throwError, of } from 'rxjs';

import { 
  User,
  CreateUserDto,
  UpdateUserDto,
  ResetPasswordDto,
  PaginatedUserResponse,
  AvailableRolesResponse,
  SearchUsersParams,
  UserRole,
  UserType,
  UserUtils,
  GlobalUsersOverview,
  UsersStatistics
} from '@core/models/dcb-bo-hub-user.model';

// Interfaces pour les nouvelles réponses
export interface TokenResponse {
  access_token: string;
  expires_in: number;
  refresh_token: string;
  refresh_expires_in: number;
  token_type: string;
  'not-before-policy': number;
  session_state: string;
  scope: string;
}

export interface UserProfileResponse {
  id: string;
  username: string;
  email: string;
  firstName: string;
  lastName: string;
  emailVerified: boolean;
  enabled: boolean;
  role: string[];
  merchantPartnerId?: string;
  createdBy?: string;
  createdByUsername?: string;
}

export interface MessageResponse {
  message: string;
}

export interface MerchantPartnerIdResponse {
  merchantPartnerId: string | null;
}

@Injectable({ providedIn: 'root' })
export class HubUsersService {
  private http = inject(HttpClient);
  private baseApiUrl = `${environment.iamApiUrl}/hub-users`;

  // === MÉTHODES SPÉCIFIQUES HUB ===
  
  getAllUsers(): Observable<GlobalUsersOverview> {
    return this.http.get<GlobalUsersOverview>(`${this.baseApiUrl}/all-users`).pipe(
      map(response => {
        // Validation de la réponse
        if (!response || !Array.isArray(response.hubUsers) || !Array.isArray(response.merchantUsers)) {
          throw new Error('Invalid response format from API');
        }
        
        return {
          ...response,
          hubUsers: response.hubUsers.map(user => this.mapToUserModel(user, UserType.HUB)),
          merchantUsers: response.merchantUsers.map(user => this.mapToUserModel(user, UserType.MERCHANT_PARTNER))
        };
      }),
      catchError(error => {
        console.error('Error loading global users overview:');
        console.error('Status:', error.status);
        console.error('Message:', error.message);
        
        if (error.status === 403) {
          console.error('Access forbidden - user may not have admin rights');
        }
        
        return throwError(() => error);
      })
    );
  }

  // Méthode pour les statistiques seulement
  getUsersStatistics(): Observable<UsersStatistics> {
    return this.http.get<GlobalUsersOverview>(`${this.baseApiUrl}`).pipe(
      map(response => response.statistics),
      catchError(error => {
        console.error('Error loading users statistics:', error);
        return throwError(() => error);
      })
    );
  }


  createHubUser(createUserDto: CreateUserDto): Observable<User> {
    // Utiliser la validation centralisée
    const errors = UserUtils.validateUserCreation(createUserDto);
    if (errors.length > 0) {
      return throwError(() => errors.join(', '));
    }

    if (!createUserDto.username?.trim()) {
      return throwError(() => 'Username is required and cannot be empty');
    }

    if (!createUserDto.email?.trim()) {
      return throwError(() => 'Email is required and cannot be empty');
    }

    if (!createUserDto.password || createUserDto.password.length < 8) {
      return throwError(() => 'Password must be at least 8 characters');
    }
    
    // Avant de créer le payload, valider les données
    if (createUserDto.userType === UserType.MERCHANT_PARTNER && !createUserDto.merchantPartnerId) {
      return throwError(() => 'merchantPartnerId is required for merchant users');
    }

    const payload = {
      username: createUserDto.username.trim(),
      email: createUserDto.email.trim().toLowerCase(), // Normaliser l'email
      firstName: createUserDto.firstName?.trim() || '',
      lastName: createUserDto.lastName?.trim() || '',
      password: createUserDto.password,
      role: createUserDto.role,
      enabled: createUserDto.enabled ?? true,
      emailVerified: createUserDto.emailVerified ?? true,
      merchantPartnerId: createUserDto.merchantPartnerId,
      userType: createUserDto.userType.trim()
    };

    // Validation supplémentaire
    if (payload.userType === UserType.HUB && payload.merchantPartnerId) {
      return throwError(() => 'merchantPartnerId should not be provided for hub users');
    }

    console.log(payload)

    return this.http.post<User>(`${this.baseApiUrl}`, payload).pipe(
      map(user => this.mapToUserModel(user, UserType.HUB)),
      catchError(error => {
        console.error('Error creating hub user:', error);
        return throwError(() => error);
      })
    );
  }

  getHubUsers(page: number = 1, limit: number = 10, filters?: SearchUsersParams): Observable<PaginatedUserResponse> {
    return this.http.get<User[]>(`${this.baseApiUrl}`).pipe(
      map(users => {
        const mappedUsers = users.map(user => this.mapToUserModel(user, UserType.HUB));
        return this.filterAndPaginateUsers(mappedUsers, page, limit, filters);
      }),
      catchError(error => {
        console.error('Error loading hub users:', error);
        return throwError(() => error);
      })
    );
  }

  getAllDcbPartners(page: number = 1, limit: number = 10, filters?: SearchUsersParams): Observable<PaginatedUserResponse> {
    return this.http.get<User[]>(`${this.baseApiUrl}/partners/dcb-partners`).pipe(
      map(users => {
        const mappedUsers = users.map(user => this.mapToUserModel(user, UserType.HUB));
        return this.filterAndPaginateUsers(mappedUsers, page, limit, filters);
      }),
      catchError(error => {
        console.error('Error loading merchant hub users:', error);
        return throwError(() => error);
      })
    );
  }

  getHubUserById(id: string): Observable<User> {
    return this.http.get<User>(`${this.baseApiUrl}/${id}`).pipe(
      map(user => this.mapToUserModel(user, UserType.HUB)),
      catchError(error => {
        console.error(`Error loading hub user ${id}:`, error);
        return throwError(() => error);
      })
    );
  }

  updateHubUser(id: string, updateUserDto: UpdateUserDto): Observable<User> {
    const payload: any = {
      firstName: updateUserDto.firstName,
      lastName: updateUserDto.lastName,
      email: updateUserDto.email,
      enabled: updateUserDto.enabled
    };

    return this.http.put<User>(`${this.baseApiUrl}/${id}`, payload).pipe(
      map(user => this.mapToUserModel(user, UserType.HUB)),
      catchError(error => {
        console.error(`Error updating hub user ${id}:`, error);
        return throwError(() => error);
      })
    );
  }

  updateHubUserRole(id: string, role: UserRole): Observable<User> {
    const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_SUPPORT, UserRole.DCB_PARTNER];
    if (!hubRoles.includes(role)) {
      return throwError(() => 'Invalid role for Hub user');
    }

    return this.http.put<User>(`${this.baseApiUrl}/${id}/role`, { role }).pipe(
      map(user => this.mapToUserModel(user, UserType.HUB)),
      catchError(error => {
        console.error(`Error updating role for hub user ${id}:`, error);
        return throwError(() => error);
      })
    );
  }

  deleteHubUser(id: string): Observable<MessageResponse> {
    return this.http.delete<MessageResponse>(`${this.baseApiUrl}/${id}`).pipe(
      catchError(error => {
        console.error(`Error deleting hub user ${id}:`, error);
        return throwError(() => error);
      })
    );
  }

  resetHubUserPassword(id: string, resetPasswordDto: ResetPasswordDto): Observable<MessageResponse> {
    const payload = {
      newPassword: resetPasswordDto.newPassword,
      temporary: resetPasswordDto.temporary !== undefined ? resetPasswordDto.temporary : true
    };

    return this.http.post<MessageResponse>(
      `${this.baseApiUrl}/${id}/reset-password`,
      payload
    ).pipe(
      catchError(error => {
        console.error(`Error resetting password for hub user ${id}:`, error);
        return throwError(() => error);
      })
    );
  }

  enableHubUser(id: string): Observable<User> {
    return this.updateHubUser(id, { enabled: true });
  }

  disableHubUser(id: string): Observable<User> {
    return this.updateHubUser(id, { enabled: false });
  }

  getAvailableHubRoles(): Observable<AvailableRolesResponse> {
    return of({
      roles: [
        {
          value: UserRole.DCB_ADMIN,
          label: 'DCB Admin',
          description: 'Full administrative access to the entire system',
          allowedForCreation: true,
          userType: UserType.HUB 
        },
        {
          value: UserRole.DCB_SUPPORT,
          label: 'DCB Support',
          description: 'Support access with limited administrative capabilities',
          allowedForCreation: true,
          userType: UserType.HUB 
        },
        {
          value: UserRole.DCB_PARTNER,
          label: 'DCB Partner',
          description: 'Partner access to merchant management',
          allowedForCreation: true,
          userType: UserType.HUB 
        }
      ]
    } as AvailableRolesResponse);
  }

  getHubUsersByRole(role: UserRole): Observable<User[]> {
    return this.http.get<User[]>(`${this.baseApiUrl}/role/${role}`).pipe(
      map(users => users.map(user => this.mapToUserModel(user, UserType.HUB))),
      catchError(error => {
        console.error(`Error loading hub users with role ${role}:`, error);
        return throwError(() => error);
      })
    );
  }

  searchHubUsers(params: SearchUsersParams): Observable<User[]> {
    return this.getHubUsers(1, 1000, params).pipe(
      map(response => response.users)
    );
  }

  hubUserExists(username: string): Observable<{ exists: boolean }> {
    return this.searchHubUsers({ query: username }).pipe(
      map(users => ({
        exists: users.some(user => user.username === username)
      })),
      catchError(error => {
        console.error('Error checking if hub user exists:', error);
        return of({ exists: false });
      })
    );
  }

    // === MÉTHODES UTILITAIRES ===

  isValidRoleForHub(role: UserRole): boolean {
    const hubRoles = [UserRole.DCB_ADMIN, UserRole.DCB_PARTNER, UserRole.DCB_SUPPORT];
    return hubRoles.includes(role);
  }

  // === MAPPING ET FILTRAGE ===

  private mapToUserModel(apiUser: any, userType: UserType): User {
    return {
      id: apiUser.id,
      username: apiUser.username,
      email: apiUser.email,
      firstName: apiUser.firstName,
      lastName: apiUser.lastName,
      enabled: apiUser.enabled,
      emailVerified: apiUser.emailVerified,
      userType: userType,
      merchantPartnerId: apiUser.merchantPartnerId,
      role: apiUser.role,
      createdBy: apiUser.createdBy,
      createdByUsername: apiUser.createdByUsername,
      createdTimestamp: apiUser.createdTimestamp,
      lastLogin: apiUser.lastLogin
    };
  }

  private filterAndPaginateUsers(
    users: User[], 
    page: number, 
    limit: number, 
    filters?: SearchUsersParams
  ): PaginatedUserResponse {
    let filteredUsers = users;
    
    if (filters) {
      if (filters.query) {
        const query = filters.query.toLowerCase();
        filteredUsers = filteredUsers.filter(user => 
          user.username.toLowerCase().includes(query) ||
          user.email.toLowerCase().includes(query) ||
          user.firstName?.toLowerCase().includes(query) ||
          user.lastName?.toLowerCase().includes(query)
        );
      }
      
      if (filters.role) {
        filteredUsers = filteredUsers.filter(user => user.role.includes(filters.role!));
      }
      
      if (filters.enabled !== undefined) {
        filteredUsers = filteredUsers.filter(user => user.enabled === filters.enabled);
      }

      if (filters.userType) {
        filteredUsers = filteredUsers.filter(user => user.userType === filters.userType);
      }

      if (filters.merchantPartnerId) {
        filteredUsers = filteredUsers.filter(user => user.merchantPartnerId === filters.merchantPartnerId);
      }
    }

    // Pagination côté client
    const startIndex = (page - 1) * limit;
    const endIndex = startIndex + limit;
    const paginatedUsers = filteredUsers.slice(startIndex, endIndex);
    
    return {
      users: paginatedUsers,
      total: filteredUsers.length,
      page,
      limit,
      totalPages: Math.ceil(filteredUsers.length / limit)
    };
  }
}