import 'dart:async';

import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';

import '../models/route_model.dart';
import './transportation_service.dart';

/// Global app state service to manage selected route across the entire app
class AppStateService extends ChangeNotifier {
  static final AppStateService _instance = AppStateService._internal();
  factory AppStateService() => _instance;
  AppStateService._internal();

  final TransportationService _transportationService = TransportationService();

  // Global state
  String? _selectedRouteId;
  String? _selectedRouteName;
  List<RouteModel> _allRoutes = [];
  bool _isLoadingRoutes = false;
  String? _error;

  // Getters
  String? get selectedRouteId => _selectedRouteId;
  String? get selectedRouteName => _selectedRouteName;
  List<RouteModel> get allRoutes => List.unmodifiable(_allRoutes);
  bool get isLoadingRoutes => _isLoadingRoutes;
  String? get error => _error;
  bool get hasSelectedRoute =>
      _selectedRouteId != null && _selectedRouteName != null;

  /// Initialize app state - call this on app start
  Future<void> initialize() async {
    await loadRoutes();
  }

  /// Load all routes from Supabase
  Future<void> loadRoutes() async {
    if (_isLoadingRoutes) return;

    _isLoadingRoutes = true;
    notifyListeners();

    try {
      final result = await _transportationService.getRoutesWithCount();
      final routes = result['data'] as List<RouteModel>;
      final count = result['count'] as int;
      final error = result['error'] as String?;

      if (error != null) {
        print('Error loading routes: $error');
        // Handle error but continue with empty list
        _allRoutes = [];
      } else {
        _allRoutes = routes;

        // Auto-select first route if none selected and routes available
        if (routes.isNotEmpty && _selectedRouteId == null) {
          await selectRoute(routes.first.id);
        }
      }

      _isLoadingRoutes = false;
      notifyListeners();

      // Show toast if no routes found as specified in requirements
      if (_allRoutes.isEmpty) {
        _showNoRoutesToast();
      }
    } catch (e) {
      print('Exception loading routes: $e');
      _allRoutes = [];
      _isLoadingRoutes = false;
      notifyListeners();

      // Show error toast for exceptions
      Fluttertoast.showToast(
        msg: "Error loading routes: ${e.toString()}",
        toastLength: Toast.LENGTH_LONG,
        gravity: ToastGravity.CENTER,
        backgroundColor: Colors.red,
        textColor: Colors.white,
        fontSize: 16.0,
      );
    }
  }

  void _showNoRoutesToast() {
    Fluttertoast.showToast(
      msg: "No routes found",
      toastLength: Toast.LENGTH_LONG,
      gravity: ToastGravity.CENTER,
      backgroundColor: Colors.orange,
      textColor: Colors.white,
      fontSize: 16.0,
    );
  }

  /// Select a route and update global state
  Future<void> selectRoute(String routeId) async {
    if (routeId == _selectedRouteId) return;

    try {
      // Find the route in our cached routes
      final route = _allRoutes.firstWhere(
        (r) => r.id == routeId,
        orElse: () => throw Exception('Route not found: $routeId'),
      );

      _selectedRouteId = routeId;
      _selectedRouteName = route.displayName;
      _error = null;

      debugPrint('✅ Route selected: $routeId - $_selectedRouteName');
      notifyListeners();
    } catch (e) {
      _error = 'Error selecting route: $e';
      debugPrint('❌ Error selecting route: $e');
      notifyListeners();
    }
  }

  /// Clear selected route
  void clearSelectedRoute() {
    _selectedRouteId = null;
    _selectedRouteName = null;
    notifyListeners();
  }

  /// Get selected route model
  RouteModel? getSelectedRoute() {
    if (_selectedRouteId == null) return null;
    try {
      return _allRoutes.firstWhere((r) => r.id == _selectedRouteId!);
    } catch (e) {
      return null;
    }
  }

  /// Private method to select first available route with stops
  Future<void> _selectFirstAvailableRoute() async {
    for (final route in _allRoutes) {
      try {
        final stops =
            await _transportationService.getRouteStopsOrderedBySeq(route.id);
        if (stops.isNotEmpty) {
          _selectedRouteId = route.id;
          _selectedRouteName = route.displayName;
          debugPrint(
              '✅ Auto-selected route: ${route.id} - ${route.displayName}');
          return;
        }
      } catch (e) {
        debugPrint('⚠️ Error checking stops for route ${route.id}: $e');
      }
    }

    // Fallback: select first route even if no stops
    if (_allRoutes.isNotEmpty) {
      final firstRoute = _allRoutes.first;
      _selectedRouteId = firstRoute.id;
      _selectedRouteName = firstRoute.displayName;
      debugPrint(
          '✅ Fallback: selected first route: ${firstRoute.id} - ${firstRoute.displayName}');
    }
  }

  /// Refresh routes and maintain selection if possible
  Future<void> refreshRoutes() async {
    final previousSelectedId = _selectedRouteId;
    await loadRoutes();

    // Try to restore previous selection
    if (previousSelectedId != null &&
        _allRoutes.any((r) => r.id == previousSelectedId)) {
      await selectRoute(previousSelectedId);
    }
  }

  /// Get route by ID
  RouteModel? getRouteById(String routeId) {
    try {
      return _allRoutes.firstWhere((r) => r.id == routeId);
    } catch (e) {
      return null;
    }
  }

  /// Check if route exists
  bool hasRoute(String routeId) {
    return _allRoutes.any((r) => r.id == routeId);
  }

  /// Show toast message for no routes found
  void showNoRoutesToast(BuildContext context) {
    if (_allRoutes.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
          content: Text('No routes found'),
          backgroundColor: Colors.orange,
          duration: Duration(seconds: 3),
        ),
      );
    }
  }
}