import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/models/marketplace.dart';
import '../../../core/services/marketplace_service.dart';

final marketplaceServiceProvider = Provider((_) => MarketplaceService());

final citiesProvider = FutureProvider<List<String>>((ref) {
  return ref.read(marketplaceServiceProvider).getCities();
});

final offersProvider = FutureProvider<List<MarketplaceOffer>>((ref) {
  return ref.read(marketplaceServiceProvider).getOffers();
});

class SearchParams {
  final String? city;
  final DateTime? startDate;
  final DateTime? endDate;
  final Set<String>? categories; // null = all; multi-select
  final String? transmission;
  final int? maxPriceCents;
  final int? minPriceCents; // client-side filter only
  final int page;

  const SearchParams({
    this.city,
    this.startDate,
    this.endDate,
    this.categories,
    this.transmission,
    this.maxPriceCents,
    this.minPriceCents,
    this.page = 1,
  });

  bool get hasDateRange => startDate != null && endDate != null;

  bool get hasFilters =>
      city != null ||
      (categories != null && categories!.isNotEmpty) ||
      transmission != null ||
      maxPriceCents != null ||
      minPriceCents != null ||
      hasDateRange;

  SearchParams copyWith({
    Object? city = _sentinel,
    DateTime? startDate,
    DateTime? endDate,
    Object? categories = _sentinel,
    Object? transmission = _sentinel,
    Object? maxPriceCents = _sentinel,
    Object? minPriceCents = _sentinel,
    int? page,
    bool clearDates = false,
  }) =>
      SearchParams(
        city: city == _sentinel ? this.city : city as String?,
        startDate: clearDates ? null : (startDate ?? this.startDate),
        endDate: clearDates ? null : (endDate ?? this.endDate),
        categories: categories == _sentinel
            ? this.categories
            : categories as Set<String>?,
        transmission: transmission == _sentinel
            ? this.transmission
            : transmission as String?,
        maxPriceCents: maxPriceCents == _sentinel
            ? this.maxPriceCents
            : maxPriceCents as int?,
        minPriceCents: minPriceCents == _sentinel
            ? this.minPriceCents
            : minPriceCents as int?,
        page: page ?? this.page,
      );

  static bool _setsEqual(Set<String>? a, Set<String>? b) {
    if (a == null && b == null) return true;
    if (a == null || b == null) return false;
    if (a.length != b.length) return false;
    return a.containsAll(b);
  }

  @override
  bool operator ==(Object other) =>
      other is SearchParams &&
      other.city == city &&
      other.startDate == startDate &&
      other.endDate == endDate &&
      _setsEqual(other.categories, categories) &&
      other.transmission == transmission &&
      other.maxPriceCents == maxPriceCents &&
      other.minPriceCents == minPriceCents &&
      other.page == page;

  @override
  int get hashCode {
    final catKey = categories == null
        ? null
        : (categories!.toList()..sort()).join(',');
    return Object.hash(city, startDate, endDate, catKey, transmission,
        maxPriceCents, minPriceCents, page);
  }
}

const _sentinel = Object();

final searchParamsProvider = StateProvider<SearchParams>((_) {
  final now = DateTime.now();
  return SearchParams(
    startDate: now,
    endDate: now.add(const Duration(days: 1)),
  );
});

final vehicleSearchProvider =
    FutureProvider.family<MarketplaceSearchResult, SearchParams>(
        (ref, params) {
  // Only send a single category to the API; multi-category is filtered client-side
  final apiCategory =
      params.categories?.length == 1 ? params.categories!.first : null;

  return ref.read(marketplaceServiceProvider).search(
        city: params.city,
        startDate: params.startDate,
        endDate: params.endDate,
        category: apiCategory,
        transmission: params.transmission,
        maxPriceCents: params.maxPriceCents,
        page: params.page,
      );
});
