import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable, BehaviorSubject, tap, catchError, throwError } from 'rxjs';
import { Router } from '@angular/router';
import { JobResponse } from './job-types';
import { API_BASE_URL } from '../config';

export interface User {
  id_usuario: number;
  username: string;
  nombre_completo: string;
  nombre_rol: string;
  sedes?: Array<{
    codigo_establecimiento: string;
    nombre_establecimiento: string;
  }>;
}

export interface LoginRequest {
  username: string;
  password: string;
}

export interface LoginResponse {
  token: string;
  usuario: User;
}

export interface RegisterRequest {
  username: string;
  email: string;
  password: string;
  nombre_completo: string;
  id_rol: number;
  sedes?: string[];
}

export interface ActualizarUsuarioPayload {
  username?: string;
  password?: string;
  email?: string;
  nombre_completo?: string;
  id_rol?: number;
}

/* Interfaz Rol para la pantalla de usuarios */
export interface Rol {
  id_rol: number;
  nombre_rol: string;
  descripcion?: string | null;
}

export interface EstadisticasAutorizacionesDia {
  fecha: string;
  total: number;
  autorizadas: number;
  no_autorizadas: number;
  pendientes: number;
}

export interface EstadisticasAutorizaciones {
  rango: { inicio: string; fin: string };
  resumen: {
    autorizadas: number;
    no_autorizadas: number;
    pendientes: number;
    total: number;
  };
  dias: EstadisticasAutorizacionesDia[];
}

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private readonly API_URL = API_BASE_URL;
  private readonly TOKEN_KEY = 'auth_token';
  private readonly USER_KEY = 'current_user';

  private currentUserSubject = new BehaviorSubject<User | null>(null);
  public currentUser$ = this.currentUserSubject.asObservable();

  private isAuthenticatedSubject = new BehaviorSubject<boolean>(false);
  public isAuthenticated$ = this.isAuthenticatedSubject.asObservable();
  private logoutTimeoutId: ReturnType<typeof setTimeout> | null = null;

  constructor(
    private http: HttpClient,
    private router: Router
  ) {
    this.initializeAuth();
  }

  private initializeAuth(): void {
    const token = this.getToken();
    const user = this.getUserFromStorage();

    if (token && user) {
      this.currentUserSubject.next(user);
      this.isAuthenticatedSubject.next(true);
      this.scheduleTokenExpiry(token);
    } else {
      this.clearAuth();
    }
  }

  // =========== LOGIN ===========

  login(credentials: LoginRequest): Observable<LoginResponse> {
    return this.http.post<LoginResponse>(`${this.API_URL}/auth/login`, credentials).pipe(
      tap(response => {
        this.setAuth(response.token, response.usuario);
      }),
      catchError((error: any) => {
        console.error('Error en login:', error);
        return throwError(() => error);
      })
    );
  }

  // =========== REGISTER (SOLO ADMIN) ===========

  register(userData: RegisterRequest): Observable<any> {
    const headers = this.getAuthHeaders();
    return this.http.post(`${this.API_URL}/auth/register`, userData, { headers }).pipe(
      catchError((error: any) => {
        console.error('Error en register:', error);
        return throwError(() => error);
      })
    );
  }

  // =========== LOGOUT ===========

  logout(): void {
    this.clearAuth();
    this.router.navigate(['/login']);
  }

  // =========== VERIFY TOKEN ===========

  verifyToken(): Observable<{ usuario: User }> {
    const headers = this.getAuthHeaders();
    return this.http.get<{ usuario: User }>(`${this.API_URL}/auth/verify`, { headers }).pipe(
      tap(response => {
        this.updateUser(response.usuario);
      })
    );
  }

  // =========== HELPERS DE AUTH ===========

  getToken(): string | null {
    return localStorage.getItem(this.TOKEN_KEY);
  }

  private setAuth(token: string, user: User): void {
    localStorage.setItem(this.TOKEN_KEY, token);
    localStorage.setItem(this.USER_KEY, JSON.stringify(user));
    this.currentUserSubject.next(user);
    this.isAuthenticatedSubject.next(true);
    this.scheduleTokenExpiry(token);
  }

  private clearAuth(): void {
    this.clearLogoutTimer();
    localStorage.removeItem(this.TOKEN_KEY);
    localStorage.removeItem(this.USER_KEY);
    this.currentUserSubject.next(null);
    this.isAuthenticatedSubject.next(false);
  }

  private scheduleTokenExpiry(token: string): void {
    const exp = this.getTokenExpiry(token);
    if (!exp) {
      return;
    }
    const timeoutMs = exp - Date.now();
    if (timeoutMs <= 0) {
      this.logout();
      return;
    }
    this.clearLogoutTimer();
    this.logoutTimeoutId = setTimeout(() => {
      this.logout();
    }, timeoutMs);
  }

  private clearLogoutTimer(): void {
    if (this.logoutTimeoutId) {
      clearTimeout(this.logoutTimeoutId);
      this.logoutTimeoutId = null;
    }
  }

  private getTokenExpiry(token: string): number | null {
    try {
      const payload = token.split('.')[1];
      if (!payload) return null;
      const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
      const padded = base64.padEnd(base64.length + (4 - (base64.length % 4)) % 4, '=');
      const decoded = JSON.parse(atob(padded));
      if (!decoded?.exp) return null;
      return decoded.exp * 1000;
    } catch {
      return null;
    }
  }

  private updateUser(user: User): void {
    localStorage.setItem(this.USER_KEY, JSON.stringify(user));
    this.currentUserSubject.next(user);
  }

  private getUserFromStorage(): User | null {
    const userStr = localStorage.getItem(this.USER_KEY);
    return userStr ? JSON.parse(userStr) : null;
  }

  getAuthHeaders(): HttpHeaders {
    const token = this.getToken();
    return new HttpHeaders({
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    });
  }

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

  isLoggedIn(): boolean {
    return this.isAuthenticatedSubject.value;
  }

  hasRole(role: string): boolean {
    const user = this.getCurrentUser();
    return user ? user.nombre_rol === role : false;
  }

  isAdministrador(): boolean {
    return this.hasRole('administrador');
  }

  isAdministrativoSede(): boolean {
    return this.hasRole('administrativo_sede');
  }

  puedeCargarPacientes(): boolean {
    return this.isAdministrador();
  }

  puedeDescargarPdfs(): boolean {
    const user = this.getCurrentUser();
    return !!user && (user.nombre_rol === 'administrador' || user.nombre_rol === 'administrativo_sede');
  }

  puedeVerTodasAutorizaciones(): boolean {
    return this.isAdministrador();
  }

  puedeGenerarAutorizaciones(): boolean {
    const user = this.getCurrentUser();
    return !!user && (user.nombre_rol === 'administrador' || user.nombre_rol === 'administrativo_sede');
  }

  tieneAccesoAEstablecimiento(codigoEstablecimiento: string): boolean {
    const user = this.getCurrentUser();
    if (!user) return false;

    if (user.nombre_rol === 'administrador') return true;

    if (user.nombre_rol === 'administrativo_sede' && user.sedes) {
      return user.sedes.some(sede => sede.codigo_establecimiento === codigoEstablecimiento);
    }

    return false;
  }

  // =========== ADMIN: USUARIOS Y REPORTES ===========

  getUsuarios(limit = 200, offset = 0): Observable<any[]> {
    const headers = this.getAuthHeaders();
    const params = { limit, offset };
    return this.http.get<any[]>(`${this.API_URL}/usuarios`, { headers, params });
  }

  cambiarEstadoUsuario(idUsuario: number, activo: boolean): Observable<any> {
    const headers = this.getAuthHeaders();
    return this.http.patch(
      `${this.API_URL}/usuarios/${idUsuario}/estado`,
      { activo },
      { headers }
    );
  }

  actualizarUsuario(idUsuario: number, payload: ActualizarUsuarioPayload): Observable<any> {
    const headers = this.getAuthHeaders();
    return this.http.patch(
      `${this.API_URL}/usuarios/${idUsuario}`,
      payload,
      { headers }
    );
  }

  // Alias usado en usuarios.ts
  actualizarEstadoUsuario(idUsuario: number, activo: boolean): Observable<any> {
    return this.cambiarEstadoUsuario(idUsuario, activo);
  }

  // Obtener autorizaciones por fecha (solo administradores)
  getAutorizacionesPorFecha(
    fechaInicio: string,
    fechaFin: string,
    limit = 500,
    offset = 0
  ): Observable<any[]> {
    const headers = this.getAuthHeaders();
    const params = { fecha_inicio: fechaInicio, fecha_fin: fechaFin, limit, offset };
    return this.http.get<any[]>(`${this.API_URL}/autorizaciones-por-fecha`, { headers, params });
  }

  // Obtener roles desde el backend
  getRoles(): Observable<Rol[]> {
    const headers = this.getAuthHeaders();
    return this.http.get<Rol[]>(`${this.API_URL}/roles`, { headers });
  }

  getEstadisticasAutorizaciones(
    fechaInicio?: string,
    fechaFin?: string
  ): Observable<EstadisticasAutorizaciones> {
    const headers = this.getAuthHeaders();
    const params: any = {};
    if (fechaInicio) params.fecha_inicio = fechaInicio;
    if (fechaFin) params.fecha_fin = fechaFin;
    return this.http.get<EstadisticasAutorizaciones>(
      `${this.API_URL}/autorizaciones-estadisticas`,
      { headers, params }
    );
  }

  crearJobPdfAutorizacion(
    numeroAutorizacion: string,
    version?: number
  ): Observable<JobResponse> {
    const headers = this.getAuthHeaders();
    const payload: any = { numero_autorizacion: numeroAutorizacion };
    if (typeof version === 'number') {
      payload.version = version;
    }
    return this.http.post<JobResponse>(
      `${this.API_URL}/jobs/autorizacion-pdf`,
      payload,
      { headers }
    );
  }

  crearJobZipAutorizaciones(fechaInicio: string, fechaFin: string): Observable<JobResponse> {
    const headers = this.getAuthHeaders();
    return this.http.post<JobResponse>(
      `${this.API_URL}/jobs/autorizaciones-zip`,
      { fecha_inicio: fechaInicio, fecha_fin: fechaFin },
      { headers }
    );
  }
}
