import { Injectable, inject, signal, OnDestroy } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '@env/environment';
import { interval, Subscription, catchError, of, tap, timeout } from 'rxjs';

export interface HealthStatus {
  status: 'Healthy' | 'Unhealthy' | 'Degraded';
  timestamp: string;
  checks: Array<{
    name: string;
    status: string;
    description?: string;
    duration: number;
  }>;
}

export interface ConnectivityState {
  isConnected: boolean;
  lastCheck: Date | null;
  error: string | null;
  checking: boolean;
}

@Injectable({ providedIn: 'root' })
export class ConnectivityService implements OnDestroy {
  private http = inject(HttpClient);
  private subscription: Subscription | null = null;
  private consecutiveFailures = 0;
  private readonly MAX_FAILURES_BEFORE_DISCONNECT = 2;

  /** Estado de conectividad reactivo */
  readonly state = signal<ConnectivityState>({
    isConnected: true, // Asumimos conectado al inicio
    lastCheck: null,
    error: null,
    checking: false,
  });

  /** Indica si hay conexión con el servidor */
  readonly isConnected = () => this.state().isConnected;

  /** Inicia el monitoreo de conectividad */
  startMonitoring(): void {
    if (this.subscription) return; // Ya está monitoreando

    // Check inicial inmediato
    this.checkHealth();

    // Polling cada N segundos
    this.subscription = interval(environment.healthCheckInterval)
      .pipe(tap(() => this.checkHealth()))
      .subscribe();
  }

  /** Detiene el monitoreo */
  stopMonitoring(): void {
    this.subscription?.unsubscribe();
    this.subscription = null;
  }

  /** Verifica la salud del servidor manualmente */
  checkHealth(): void {
    this.state.update(s => ({ ...s, checking: true }));

    this.http.get<HealthStatus>(environment.healthCheckUrl)
      .pipe(
        timeout(4000), // Timeout de 4 segundos
        catchError(error => {
          this.handleError(error);
          return of(null);
        })
      )
      .subscribe(response => {
        if (response) {
          this.handleSuccess(response);
        }
      });
  }

  private handleSuccess(response: HealthStatus): void {
    this.consecutiveFailures = 0;
    const dbCheck = response.checks.find(c => c.name === 'database');
    const isDbHealthy = dbCheck?.status === 'Healthy';

    this.state.set({
      isConnected: response.status === 'Healthy' && isDbHealthy,
      lastCheck: new Date(),
      error: isDbHealthy ? null : 'La base de datos no está disponible',
      checking: false,
    });
  }

  private handleError(error: unknown): void {
    this.consecutiveFailures++;

    // Solo marcar como desconectado después de varios fallos consecutivos
    // para evitar falsos positivos por latencia de red
    const shouldDisconnect = this.consecutiveFailures >= this.MAX_FAILURES_BEFORE_DISCONNECT;

    let errorMessage = 'No se pudo conectar con el servidor';

    if (error instanceof Error) {
      if (error.name === 'TimeoutError') {
        errorMessage = 'El servidor no responde (timeout)';
      } else if (error.message.includes('0 Unknown Error')) {
        errorMessage = 'El servidor no está disponible. Verifica que esté en ejecución.';
      }
    }

    this.state.set({
      isConnected: !shouldDisconnect,
      lastCheck: new Date(),
      error: shouldDisconnect ? errorMessage : null,
      checking: false,
    });
  }

  ngOnDestroy(): void {
    this.stopMonitoring();
  }
}
