// Сервис управления подключением к серверу
export type ConnectionStatus = 'connected' | 'connecting' | 'disconnected';

type ConnectionStatusCallback = (status: ConnectionStatus) => void;

class ConnectionService {
  private status: ConnectionStatus = 'disconnected';
  private listeners: Set<ConnectionStatusCallback> = new Set();
  private reconnectInterval: number | null = null;
  private reconnectAttempts = 0;
  private maxReconnectAttempts = Infinity; // Бесконечные попытки
  private reconnectDelay = 3000; // 3 секунды между попытками
  private checkInterval: number | null = null;
  private apiBaseUrl: string;

  constructor() {
    this.apiBaseUrl = import.meta.env.VITE_API_BASE_URL || '';

    // Если API не настроен, сразу устанавливаем статус connected
    if (!this.apiBaseUrl) {
      this.setStatus('connected');
      return;
    }
    
    this.startConnectionCheck();
    this.initializeConnection();
  }

  // Инициализация подключения
  private async initializeConnection() {
    if (!this.apiBaseUrl) {
      // Если API не настроен, считаем что подключение не требуется (используется localStorage)
      this.setStatus('connected');
      return;
    }

    this.setStatus('connecting');
    await this.checkConnection();
  }

  // Проверка подключения
  private async checkConnection(): Promise<boolean> {
    if (!this.apiBaseUrl) {
      this.setStatus('connected');
      return true;
    }

    try {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => controller.abort(), 3000); // 3 секунды таймаут

      // Пробуем несколько endpoints для проверки подключения
      const endpoints = ['/health', '/districts', '/buildings'];
      let connected = false;
      let lastError: Error | null = null;

      for (const endpoint of endpoints) {
        try {
          const response = await fetch(`${this.apiBaseUrl}${endpoint}`, {
            method: 'GET',
            signal: controller.signal,
            cache: 'no-cache',
            headers: {
              'Content-Type': 'application/json',
            },
          });

          // Если получили ответ (даже с ошибкой 404, 403 и т.д.), сервер доступен
          // 404 означает, что сервер работает, но endpoint не найден - это нормально
          if (response.status < 500) {
            connected = true;
            break;
          }
        } catch (e) {
          lastError = e instanceof Error ? e : new Error(String(e));
          // Пробуем следующий endpoint
          continue;
        }
      }

      clearTimeout(timeoutId);

      if (connected) {
        this.setStatus('connected');
        this.reconnectAttempts = 0;
        this.stopReconnect();
        return true;
      } else {
        // Проверяем, не была ли это ошибка сети (CORS, таймаут и т.д.)
        const isNetworkError = lastError && (
          lastError.name === 'AbortError' ||
          lastError.message.includes('Failed to fetch') ||
          lastError.message.includes('NetworkError') ||
          lastError.message.includes('CORS')
        );

        if (isNetworkError) {
          this.setStatus('disconnected');
          this.startReconnect();
          return false;
        } else {
          // Если это не ошибка сети, возможно сервер работает, но endpoint недоступен
          // В этом случае считаем что подключение есть
          this.setStatus('connected');
          this.stopReconnect();
          return true;
        }
      }
    } catch (error) {
      // Общая ошибка - считаем что нет подключения
      this.setStatus('disconnected');
      this.startReconnect();
      return false;
    }
  }

  // Установка статуса и уведомление слушателей
  private setStatus(newStatus: ConnectionStatus) {
    if (this.status !== newStatus) {
      this.status = newStatus;
      this.listeners.forEach(callback => callback(newStatus));
    }
  }

  // Начало процесса переподключения
  private startReconnect() {
    if (this.reconnectInterval) {
      return; // Уже переподключаемся
    }

    if (this.reconnectAttempts >= this.maxReconnectAttempts) {
      return; // Достигнут лимит попыток
    }

    this.reconnectInterval = window.setInterval(async () => {
      this.reconnectAttempts++;
      this.setStatus('connecting');
      
      const connected = await this.checkConnection();
      
      if (connected) {
        this.stopReconnect();
      }
    }, this.reconnectDelay);
  }

  // Остановка процесса переподключения
  private stopReconnect() {
    if (this.reconnectInterval) {
      clearInterval(this.reconnectInterval);
      this.reconnectInterval = null;
    }
    this.reconnectAttempts = 0;
  }

  // Периодическая проверка подключения
  private startConnectionCheck() {
    // Проверяем каждые 10 секунд
    this.checkInterval = window.setInterval(async () => {
      if (this.status === 'connected') {
        await this.checkConnection();
      }
    }, 10000);
  }

  // Получить текущий статус
  getStatus(): ConnectionStatus {
    return this.status;
  }

  // Подписаться на изменения статуса
  subscribe(callback: ConnectionStatusCallback): () => void {
    this.listeners.add(callback);
    // Сразу вызываем callback с текущим статусом
    callback(this.status);
    
    // Возвращаем функцию отписки
    return () => {
      this.listeners.delete(callback);
    };
  }

  // Принудительная проверка подключения
  async forceCheck(): Promise<boolean> {
    if (!this.apiBaseUrl) {
      // Если API не настроен, считаем что подключение не требуется
      this.setStatus('connected');
      return true;
    }
    this.setStatus('connecting');
    return await this.checkConnection();
  }

  // Очистка ресурсов
  destroy() {
    this.stopReconnect();
    if (this.checkInterval) {
      clearInterval(this.checkInterval);
      this.checkInterval = null;
    }
    this.listeners.clear();
  }
}

// Создаём единственный экземпляр сервиса
export const connectionService = new ConnectionService();
