import { Injectable, inject } from '@angular/core';
import { HttpClient } 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
} 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;
}

// ===== SERVICE UTILISATEURS MERCHANT =====

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

  getUserMerchantPartnerId(userId: string): Observable<string | null> {
    return this.http.get<MerchantPartnerIdResponse>(`${this.baseApiUrl}/merchant-partner/${userId}`).pipe(
      map(response => response.merchantPartnerId),
      catchError(error => {
        console.error(`Error loading merchant partner ID for user ${userId}:`, error);
        return throwError(() => error);
      })
    );
  }

// === MÉTHODES SPÉCIFIQUES MERCHANT ===

  createMerchantUser(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');
    }

    // Adapter le payload pour le nouveau contrôleur
    const payload = {
      username: createUserDto.username.trim(),
      email: createUserDto.email.trim(),
      firstName: (createUserDto.firstName || '').trim(),
      lastName: (createUserDto.lastName || '').trim(),
      password: createUserDto.password,
      role: createUserDto.role,
      enabled: createUserDto.enabled !== undefined ? createUserDto.enabled : true,
      emailVerified: createUserDto.emailVerified !== undefined ? createUserDto.emailVerified : true,
      merchantPartnerId: createUserDto.merchantPartnerId?.trim() || null,
      userType: createUserDto.userType.trim()
    };

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

  getMyMerchantUsers(): Observable<User[]> {
    return this.http.get<User[]>(`${this.baseApiUrl}`).pipe(
      map(users => users.map(user => this.mapToUserModel(user, UserType.MERCHANT_PARTNER))),
      catchError(error => {
        console.error('Error loading my merchant users:', error);
        return throwError(() => error);
      })
    );
  }

  getMerchantUsersByPartner(partnerId: string): Observable<User[]> {
    return this.getMyMerchantUsers().pipe(
      map(users => users.filter(user => user.merchantPartnerId === partnerId))
    );
  }

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

  getMerchantUsers(page: number = 1, limit: number = 10, filters?: SearchUsersParams): Observable<PaginatedUserResponse> {
    return this.getMyMerchantUsers().pipe(
      map(users => this.filterAndPaginateUsers(users, page, limit, filters)),
      catchError(error => {
        console.error('Error loading merchant users:', error);
        return throwError(() => error);
      })
    );
  }

  updateMerchantUser(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.MERCHANT_PARTNER)),
      catchError(error => {
        console.error(`Error updating merchant user ${id}:`, error);
        return throwError(() => error);
      })
    );
  }

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

  resetMerchantUserPassword(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 merchant user ${id}:`, error);
        return throwError(() => error);
      })
    );
  }

  updateMerchantUserRole(id: string, role: UserRole): Observable<User> {
    const merchantRoles = [UserRole.DCB_PARTNER_ADMIN, UserRole.DCB_PARTNER_SUPPORT, UserRole.DCB_PARTNER_MANAGER];
    if (!merchantRoles.includes(role)) {
      return throwError(() => 'Invalid role for Merchant user');
    }

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

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

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

  getAvailableMerchantRoles(): Observable<AvailableRolesResponse> {
    return of({
      roles: [
        {
          value: UserRole.DCB_PARTNER_ADMIN,
          label: 'Partner Admin',
          description: 'Full administrative access within the merchant partner',
          allowedForCreation: true,
          userType: UserType.MERCHANT_PARTNER 
        },
        {
          value: UserRole.DCB_PARTNER_MANAGER,
          label: 'Partner Manager',
          description: 'Manager access with limited administrative capabilities',
          allowedForCreation: true,
          userType: UserType.MERCHANT_PARTNER 
        },
        {
          value: UserRole.DCB_PARTNER_SUPPORT,
          label: 'Partner Support',
          description: 'Support role with read-only and basic operational access',
          allowedForCreation: true,
          userType: UserType.MERCHANT_PARTNER 
        }
      ]
    } as AvailableRolesResponse);
  }

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

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

  getMerchantUsersByRole(role: UserRole): Observable<User[]> {
    return this.searchMerchantUsers({ role });
  }

  getActiveMerchantUsers(): Observable<User[]> {
    return this.searchMerchantUsers({ enabled: true });
  }

  getInactiveMerchantUsers(): Observable<User[]> {
    return this.searchMerchantUsers({ enabled: false });
  }

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

  isValidRoleForMerchant(role: UserRole): boolean {
    const merchantRoles = [UserRole.DCB_PARTNER_ADMIN, UserRole.DCB_PARTNER_MANAGER, UserRole.DCB_PARTNER_SUPPORT];
    return merchantRoles.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, // Convertir le rôle unique en tableau
      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)
    };
  }
}
