import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../api/types.dart';
import '../api/client.dart';
import '../api/openapi_config.dart';
import '../services/auth_service.dart';
import '../models/user_profile.dart';
import '../models/delivery_route.dart';
import '../models/delivery.dart';

final authServiceProvider = Provider<AuthService>((ref) {
  return AuthService(config: AuthConfig.development);
});

final apiClientProvider = Provider<CqrsApiClient>((ref) {
  final authService = ref.watch(authServiceProvider);
  return CqrsApiClient(
    config: ApiClientConfig.development,
    authService: authService,
  );
});

final isAuthenticatedProvider = FutureProvider<bool>((ref) async {
  final authService = ref.watch(authServiceProvider);
  return await authService.isAuthenticated();
});

final userProfileProvider = FutureProvider<UserProfile?>((ref) async {
  final authService = ref.watch(authServiceProvider);
  final token = await authService.getToken();
  if (token == null) return null;
  return authService.decodeToken(token);
});

final authTokenProvider = FutureProvider<String?>((ref) async {
  final authService = ref.watch(authServiceProvider);
  return await authService.getToken();
});

final deliveryRoutesProvider = FutureProvider<List<DeliveryRoute>>((ref) async {
  final authService = ref.watch(authServiceProvider);
  final isAuthenticated = await authService.isAuthenticated();

  if (!isAuthenticated) {
    throw Exception('User not authenticated');
  }

  // Create a new client with auth service for automatic token refresh
  final authClient = CqrsApiClient(
    config: ApiClientConfig.development,
    authService: authService,
  );

  final result = await authClient.executeQuery<List<DeliveryRoute>>(
    endpoint: 'simpleDeliveryRouteQueryItems',
    query: _EmptyQuery(),
    fromJson: (json) {
      // API returns data wrapped in object with "data" field
      final data = json['data'];
      if (data is List<dynamic>) {
        return data.map((r) => DeliveryRoute.fromJson(r as Map<String, dynamic>)).toList();
      }
      return [];
    },
  );

  return result.whenSuccess((routes) => routes) ?? [];
});

final deliveriesProvider = FutureProvider.family<List<Delivery>, int>((ref, routeFragmentId) async {
  final authService = ref.watch(authServiceProvider);
  final isAuthenticated = await authService.isAuthenticated();

  if (!isAuthenticated) {
    throw Exception('User not authenticated');
  }

  final authClient = CqrsApiClient(
    config: ApiClientConfig.development,
    authService: authService,
  );

  final result = await authClient.executeQuery<List<Delivery>>(
    endpoint: 'simpleDeliveriesQueryItems',
    query: _DeliveriesQuery(routeFragmentId: routeFragmentId),
    fromJson: (json) {
      // API returns data wrapped in object with "data" field
      final data = json['data'];
      if (data is List<dynamic>) {
        return data.map((d) => Delivery.fromJson(d as Map<String, dynamic>)).toList();
      }
      return [];
    },
  );

  // Log error if API call failed
  result.whenError((error) {
    debugPrint('ERROR fetching deliveries for route $routeFragmentId: ${error.message}');
    if (error.originalException != null) {
      debugPrint('Original exception: ${error.originalException}');
    }
  });

  final deliveries = result.whenSuccess((deliveries) => deliveries) ?? [];

  // Always append the warehouse delivery at the end
  return [...deliveries, Delivery.createWarehouseDelivery()];
});

/// Provider to get all deliveries from all routes
final allDeliveriesProvider = FutureProvider<List<Delivery>>((ref) async {
  final routes = await ref.read(deliveryRoutesProvider.future);

  if (routes.isEmpty) {
    return [];
  }

  // Fetch deliveries for all routes in parallel using Future.wait
  final deliveriesFutures = routes.map((route) {
    return ref.read(deliveriesProvider(route.id).future);
  }).toList();

  // Wait for all futures to complete
  final deliveriesLists = await Future.wait(deliveriesFutures);

  // Combine all deliveries into a single list
  final allDeliveries = <Delivery>[];
  for (final deliveries in deliveriesLists) {
    allDeliveries.addAll(deliveries);
  }

  return allDeliveries;
});

// Language notifier for state management with SharedPreferences persistence
class LanguageNotifier extends AsyncNotifier<String> {
  static const String _languageKey = 'app_language';

  @override
  Future<String> build() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getString(_languageKey) ?? 'system';
  }

  Future<void> setLanguage(String lang) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_languageKey, lang);
    state = AsyncValue.data(lang);
  }
}

final languageProvider = AsyncNotifierProvider<LanguageNotifier, String>(() {
  return LanguageNotifier();
});

// Theme mode notifier for manual theme switching
class ThemeModeNotifier extends Notifier<ThemeMode> {
  @override
  ThemeMode build() => ThemeMode.dark;

  void setThemeMode(ThemeMode mode) => state = mode;
}

final themeModeProvider = NotifierProvider<ThemeModeNotifier, ThemeMode>(() {
  return ThemeModeNotifier();
});

// Collapse state notifier for sidebar persistence
class CollapseStateNotifier extends Notifier<bool> {
  @override
  bool build() => true; // Default: expanded

  void toggle() => state = !state;
  void setExpanded(bool expanded) => state = expanded;
}

final collapseStateProvider = NotifierProvider<CollapseStateNotifier, bool>(() {
  return CollapseStateNotifier();
});

// Mobile deliveries list toggle state notifier for mobile overlay
class MobileDeliveriesListOpenNotifier extends Notifier<bool> {
  @override
  bool build() => false; // Default: closed

  void toggle() => state = !state;
  void setOpen(bool open) => state = open;
}

final mobileDeliveriesListOpenProvider = NotifierProvider<MobileDeliveriesListOpenNotifier, bool>(() {
  return MobileDeliveriesListOpenNotifier();
});

class _EmptyQuery implements Serializable {
  @override
  Map<String, Object?> toJson() => {};
}

class _DeliveriesQuery implements Serializable {
  final int routeFragmentId;

  _DeliveriesQuery({required this.routeFragmentId});

  @override
  Map<String, Object?> toJson() => {
    'params': {
      'routeFragmentId': routeFragmentId,
    },
  };
}
