import 'dart:async';
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:geosector_app/core/data/models/user_model.dart';
import 'package:geosector_app/core/constants/app_keys.dart';
import 'package:retry/retry.dart';
import 'package:universal_html/html.dart' as html;

class ApiService {
  final Dio _dio = Dio();
  late final String _baseUrl;
  late final String _appIdentifier;
  String? _sessionId;
  
  // Détermine l'environnement actuel (DEV, REC, PROD) en fonction de l'URL
  String _determineEnvironment() {
    if (!kIsWeb) {
      // En mode non-web, utiliser l'environnement de développement par défaut
      return 'DEV';
    }
    
    final currentUrl = html.window.location.href.toLowerCase();
    
    if (currentUrl.contains('dapp.geosector.fr')) {
      return 'DEV';
    } else if (currentUrl.contains('rapp.geosector.fr')) {
      return 'REC';
    } else {
      return 'PROD';
    }
  }
  
  // Configure l'URL de base API et l'identifiant d'application selon l'environnement
  void _configureEnvironment() {
    final env = _determineEnvironment();
    
    switch (env) {
      case 'DEV':
        _baseUrl = AppKeys.baseApiUrlDev;
        _appIdentifier = AppKeys.appIdentifierDev;
        break;
      case 'REC':
        _baseUrl = AppKeys.baseApiUrlRec;
        _appIdentifier = AppKeys.appIdentifierRec;
        break;
      default: // PROD
        _baseUrl = AppKeys.baseApiUrlProd;
        _appIdentifier = AppKeys.appIdentifierProd;
    }
    
    debugPrint('GEOSECTOR 🔗 Environnement: $env, API: $_baseUrl');
  }

  ApiService() {
    // Configurer l'environnement
    _configureEnvironment();
    
    // Configurer Dio
    _dio.options.baseUrl = _baseUrl;
    _dio.options.connectTimeout = AppKeys.connectionTimeout;
    _dio.options.receiveTimeout = AppKeys.receiveTimeout;
    
    // Ajouter les en-têtes par défaut avec l'identifiant d'application adapté à l'environnement
    final headers = Map<String, String>.from(AppKeys.defaultHeaders);
    headers['X-App-Identifier'] = _appIdentifier;
    
    _dio.options.headers.addAll(headers);

    // Ajouter des intercepteurs pour l'authentification par session
    _dio.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {
      // Ajouter le session_id comme token Bearer aux en-têtes si disponible
      if (_sessionId != null) {
        options.headers[AppKeys.sessionHeader] = 'Bearer $_sessionId';
      }
      return handler.next(options);
    }, onError: (DioException error, handler) {
      // Gérer les erreurs d'authentification (401)
      if (error.response?.statusCode == 401) {
        // Session expirée ou invalide
        _sessionId = null;
      }
      return handler.next(error);
    }));
  }

  // Définir l'ID de session
  void setSessionId(String? sessionId) {
    _sessionId = sessionId;
  }
  
  // Obtenir l'environnement actuel (utile pour le débogage)
  String getCurrentEnvironment() {
    return _determineEnvironment();
  }
  
  // Obtenir l'URL API actuelle (utile pour le débogage)
  String getCurrentApiUrl() {
    return _baseUrl;
  }
  
  // Obtenir l'identifiant d'application actuel (utile pour le débogage)
  String getCurrentAppIdentifier() {
    return _appIdentifier;
  }

  // Vérifier la connectivité réseau
  Future<bool> hasInternetConnection() async {
    final connectivityResult = await (Connectivity().checkConnectivity());
    return connectivityResult != ConnectivityResult.none;
  }

  // Méthode POST générique
  Future<Response> post(String path, {dynamic data}) async {
    try {
      return await _dio.post(path, data: data);
    } catch (e) {
      rethrow;
    }
  }
  
  // Méthode GET générique
  Future<Response> get(String path, {Map<String, dynamic>? queryParameters}) async {
    try {
      return await _dio.get(path, queryParameters: queryParameters);
    } catch (e) {
      rethrow;
    }
  }
  
  // Méthode PUT générique
  Future<Response> put(String path, {dynamic data}) async {
    try {
      return await _dio.put(path, data: data);
    } catch (e) {
      rethrow;
    }
  }
  
  // Méthode DELETE générique
  Future<Response> delete(String path) async {
    try {
      return await _dio.delete(path);
    } catch (e) {
      rethrow;
    }
  }

  // Authentification avec PHP session
  Future<Map<String, dynamic>> login(String username, String password, {required String type}) async {
    try {
      final response = await _dio.post(AppKeys.loginEndpoint, data: {
        'username': username,
        'password': password,
        'type': type, // Ajouter le type de connexion (user ou admin)
      });

      // Vérifier la structure de la réponse
      final data = response.data as Map<String, dynamic>;
      final status = data['status'] as String?;
      
      // Afficher le message en cas d'erreur
      if (status != 'success') {
        final message = data['message'] as String?;
        debugPrint('Erreur d\'authentification: $message');
      }

      // Si le statut est 'success', récupérer le session_id
      if (status == 'success' && data.containsKey('session_id')) {
        final sessionId = data['session_id'];
        // Définir la session pour les futures requêtes
        if (sessionId != null) {
          setSessionId(sessionId);
        }
      }

      return data;
    } catch (e) {
      rethrow;
    }
  }

  // Déconnexion
  Future<void> logout() async {
    try {
      if (_sessionId != null) {
        await _dio.post(AppKeys.logoutEndpoint);
        _sessionId = null;
      }
    } catch (e) {
      // Même en cas d'erreur, on réinitialise la session
      _sessionId = null;
      rethrow;
    }
  }

  // Utilisateurs
  Future<List<UserModel>> getUsers() async {
    try {
      final response = await retry(
        () => _dio.get('/users'),
        retryIf: (e) => e is SocketException || e is TimeoutException,
      );

      return (response.data as List)
          .map((json) => UserModel.fromJson(json))
          .toList();
    } catch (e) {
      // Gérer les erreurs
      rethrow;
    }
  }

  Future<UserModel> getUserById(int id) async {
    try {
      final response = await _dio.get('/users/$id');
      return UserModel.fromJson(response.data);
    } catch (e) {
      rethrow;
    }
  }

  Future<UserModel> createUser(UserModel user) async {
    try {
      final response = await _dio.post('/users', data: user.toJson());
      return UserModel.fromJson(response.data);
    } catch (e) {
      rethrow;
    }
  }

  Future<UserModel> updateUser(UserModel user) async {
    try {
      final response = await _dio.put('/users/${user.id}', data: user.toJson());
      return UserModel.fromJson(response.data);
    } catch (e) {
      rethrow;
    }
  }

  Future<void> deleteUser(String id) async {
    try {
      await _dio.delete('/users/$id');
    } catch (e) {
      rethrow;
    }
  }

  // Espace réservé pour les futures méthodes de gestion des profils

  // Espace réservé pour les futures méthodes de gestion des données

  // Synchronisation en batch
  Future<Map<String, dynamic>> syncData({
    List<UserModel>? users,
  }) async {
    try {
      final Map<String, dynamic> payload = {
        if (users != null) 'users': users.map((u) => u.toJson()).toList(),
      };

      final response = await _dio.post('/sync', data: payload);
      return response.data;
    } catch (e) {
      rethrow;
    }
  }
}
