import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import { User } from '../models/user.model';
import { environment } from '../../environments/environment';
import { StorageService } from './storage.service';

// Clave para almacenar información de sesión
const AUTH_TOKEN_KEY = 'auth_token';
const USER_KEY = 'user_data';

// Interfaz para credenciales de login
interface LoginCredentials {
  email: string;
  password: string;
}

// Interfaz para datos de registro
interface RegisterData {
  name: string;
  email: string;
  password: string;
}

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private apiUrl = `${environment.apiUrl}/api/users`;
  private authUrl = `${environment.apiUrl}/api/auth`;
  private currentUserSubject = new BehaviorSubject<User | null>(null);
  public currentUser$ = this.currentUserSubject.asObservable();
  private isInitialized = false;
  
  constructor(
    private http: HttpClient,
    private storageService: StorageService
  ) {
    // Intentar recuperar sesión anterior
    this.initializeSession();
  }

  /**
   * Inicializa la sesión si hay datos guardados
   */
  async initializeSession() {
    if (this.isInitialized) return;
    
    try {
      const userData = await this.storageService.get(USER_KEY) as User | null;
      
      if (userData) {
        console.log('Sesión recuperada del almacenamiento local:', userData);
        // Normalizar campos para compatibilidad
        this.normalizeUserData(userData);
        this.currentUserSubject.next(userData);
      } else {
        console.log('No hay sesión guardada, redirigiendo a login');
        this.currentUserSubject.next(null);
      }
    } catch (error) {
      console.error('Error al inicializar sesión:', error);
      this.currentUserSubject.next(null);
    }
    
    this.isInitialized = true;
  }
  
  /**
   * Espera a que se complete la inicialización
   * Importante para evitar redirecciones erróneas cuando la app inicia
   */
  async waitForInitialization(): Promise<void> {
    if (this.isInitialized) return;
    
    // Si no se ha inicializado, iniciamos el proceso
    await this.initializeSession();
    
    // Esperar hasta que se inicialice (con timeout)
    let attempts = 0;
    while (!this.isInitialized && attempts < 10) {
      await new Promise(resolve => setTimeout(resolve, 100));
      attempts++;
    }
  }

  /**
   * Normaliza los datos de usuario para compatibilidad entre frontend/backend
   */
  private normalizeUserData(user: User) {
    // Sincronizar campos de imagen
    if (user.profilePicUrl && !user.profilePic) {
      user.profilePic = user.profilePicUrl;
    } else if (user.profilePic && !user.profilePicUrl) {
      user.profilePicUrl = user.profilePic;
    }
    
    // Sincronizar preferencias de notificaciones
    if (user.notificationsEnabled !== undefined && !user.preferences) {
      user.preferences = {
        notifications: user.notificationsEnabled,
        favoriteClasses: []
      };
    } else if (user.preferences?.notifications !== undefined && user.notificationsEnabled === undefined) {
      user.notificationsEnabled = user.preferences.notifications;
    }
  }


  getCurrentUser(): User | null {
    return this.currentUserSubject.value;
  }

  /**
   * Iniciar sesión con email y contraseña
   */
  login(credentials: LoginCredentials): Observable<User> {
    console.log('Intentando login con:', credentials);
    return this.http.post<any>(`${this.authUrl}/login`, credentials).pipe(
      tap(async (response) => {
        console.log('Respuesta de login:', response);
        
        // Guardar token si el backend lo devuelve
        if (response.token) {
          await this.storageService.set(AUTH_TOKEN_KEY, response.token);
        }
        
        // Verificar y normalizar datos del usuario
        const user = response.user || response;
        this.normalizeUserData(user);
        
        // Guardar datos del usuario
        await this.storageService.set(USER_KEY, user);
        
        // Actualizar estado de sesión
        this.currentUserSubject.next(user);
      }),
      map(response => response.user || response)
    );
  }
  
  /**
   * Registrar un nuevo usuario
   */
  register(userData: RegisterData): Observable<User> {
    console.log('Registrando usuario:', userData);
    const registerData = {
      name: userData.name,
      email: userData.email,
      password: userData.password
    };
    
    return this.http.post<any>(`${this.authUrl}/register`, registerData).pipe(
      tap(async (response) => {
        console.log('Respuesta de registro:', response);
        
        // Guardar token si el backend lo devuelve
        if (response.token) {
          await this.storageService.set(AUTH_TOKEN_KEY, response.token);
        }
        
        // Verificar y normalizar datos del usuario
        const user = response.user || response;
        this.normalizeUserData(user);
        
        // Guardar datos del usuario
        await this.storageService.set(USER_KEY, user);
        
        // Actualizar estado de sesión
        this.currentUserSubject.next(user);
      }),
      map(response => response.user || response)
    );
  }

  /**
   * Método para simular login/registro en una app de demo
   */
  simulateAuth(userData: User): Observable<User> {
    return of(userData).pipe(
      tap(async (user) => {
        this.normalizeUserData(user);
        await this.storageService.set(USER_KEY, user);
        this.currentUserSubject.next(user);
      })
    );
  }

  updateUserProfile(userData: Partial<User>): Observable<User> {
    const currentUser = this.getCurrentUser();
    if (!currentUser) {
      return of(currentUser as unknown as User);
    }

    console.log('Actualizando perfil de usuario con:', userData);
    
    // Asegurar que ambos campos de imagen estén sincronizados
    if (userData.profilePic && !userData.profilePicUrl) {
      userData.profilePicUrl = userData.profilePic;
    } else if (userData.profilePicUrl && !userData.profilePic) {
      userData.profilePic = userData.profilePicUrl;
    }
    
    // Sincronizar notificaciones entre los dos formatos
    if (userData.preferences?.notifications !== undefined && userData.notificationsEnabled === undefined) {
      userData.notificationsEnabled = userData.preferences.notifications;
    } else if (userData.notificationsEnabled !== undefined && 
               (!userData.preferences || userData.preferences.notifications === undefined)) {
      if (!userData.preferences) userData.preferences = { notifications: false, favoriteClasses: [] };
      userData.preferences.notifications = userData.notificationsEnabled;
    }

    // Solo enviamos al servidor los campos que espera
    const backendUserData = {
      name: userData.name,
      profilePicUrl: userData.profilePicUrl,
      notificationsEnabled: userData.notificationsEnabled || 
                          (userData.preferences ? userData.preferences.notifications : undefined)
    };

    return this.http.put<User>(`${this.apiUrl}/${currentUser.id}`, backendUserData).pipe(
      tap(async (user) => {
        console.log('Usuario actualizado correctamente:', user);
        
        // Sincronizar campos para mantener compatibilidad
        if (user.profilePicUrl && !user.profilePic) {
          user.profilePic = user.profilePicUrl;
        } else if (user.profilePic && !user.profilePicUrl) {
          user.profilePicUrl = user.profilePic;
        }
        
        // Mantener los campos que espera el frontend
        if (user.notificationsEnabled !== undefined && !user.preferences) {
          user.preferences = {
            notifications: user.notificationsEnabled,
            favoriteClasses: currentUser.preferences?.favoriteClasses || []
          };
        }
        
        // Actualizar almacenamiento local
        await this.storageService.set(USER_KEY, user);
        
        this.currentUserSubject.next(user);
      }),
      catchError(error => {
        console.error('Error al actualizar usuario:', error);
        // Devolver el usuario actualizado localmente para que la UI no se rompa
        // en caso de error de red
        const updatedUser = { ...currentUser, ...userData };
        this.currentUserSubject.next(updatedUser);
        return of(updatedUser);
      })
    );
  }

  /**
   * Cerrar sesión y eliminar datos
   */
  async logout(): Promise<boolean> {
    try {
      // En una aplicación real, enviaríamos petición al backend
      // this.http.post(`${this.authUrl}/logout`, {}).subscribe();
      
      // Limpiar datos de sesión
      await this.storageService.clear(); // Limpiamos TODA la caché de preferencias
      
      // Actualizar estado
      this.currentUserSubject.next(null);
      this.isInitialized = false; // Permitir nueva inicialización
      
      return true;
    } catch (error) {
      console.error('Error al cerrar sesión:', error);
      return false;
    }
  }
  
  /**
   * Verificar si hay sesión activa
   */
  isLoggedIn(): boolean {
    return !!this.currentUserSubject.value;
  }
}