
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hive_flutter/hive_flutter.dart';
import '../models/sake_item.dart';
import 'filter_providers.dart';

// 1. Raw List Stream
final rawSakeListItemsProvider = StreamProvider<List<SakeItem>>((ref) {
  final box = Hive.box<SakeItem>('sake_items');
  // Use startWith to emit current value immediately
  return box.watch().map((event) => box.values.toList()).startWith(box.values.toList());
});

// 2. Sort Order Stream
final sakeSortOrderProvider = StreamProvider<List<String>>((ref) {
  final box = Hive.box('settings');
  return box.watch(key: 'sake_sort_order').map((event) {
    final List<dynamic>? stored = box.get('sake_sort_order');
    return stored?.cast<String>() ?? <String>[];
  }).startWith(box.get('sake_sort_order')?.cast<String>() ?? []);
});

// Sort Mode Enum
enum SortMode { newest, oldest, name, custom }

class SakeSortModeNotifier extends Notifier<SortMode> {
  @override
  SortMode build() => SortMode.newest;
  
  void set(SortMode mode) => state = mode;
}

final sakeSortModeProvider = NotifierProvider<SakeSortModeNotifier, SortMode>(SakeSortModeNotifier.new);

// 3. Combined Sorted List
final sakeListProvider = Provider<AsyncValue<List<SakeItem>>>((ref) {
  final rawListAsync = ref.watch(rawSakeListItemsProvider);
  final sortOrderAsync = ref.watch(sakeSortOrderProvider);
  final sortMode = ref.watch(sakeSortModeProvider);
  
  // Watch Filters
  final searchQuery = ref.watch(sakeSearchQueryProvider).toLowerCase();
  final showFavoritesOnly = ref.watch(sakeFilterFavoriteProvider);
  final filterTag = ref.watch(sakeFilterTagProvider);
  final filterPrefecture = ref.watch(sakeFilterPrefectureProvider);

  return rawListAsync.when(
    data: (rawList) {
      if (rawList.isEmpty) return const AsyncValue.data([]);

      // 1. First, apply filters to raw list
      var filtered = rawList.where((item) {
        // Search Filter
        if (searchQuery.isNotEmpty) {
           final matches = item.displayData.name.toLowerCase().contains(searchQuery) ||
                          item.displayData.brewery.toLowerCase().contains(searchQuery) ||
                          item.displayData.prefecture.toLowerCase().contains(searchQuery);
           if (!matches) return false;
        }

        // Favorite Filter
        if (showFavoritesOnly) {
          if (!item.userData.isFavorite) return false;
        }

        // Prefecture Filter
        if (filterPrefecture != null) {
           if (item.displayData.prefecture != filterPrefecture) return false;
        }

        // Tag Filter
        if (filterTag != null && filterTag != 'All') {
            // Special case for 'Set' which effectively filters by itemType if we had it, or implicit tag
            if (filterTag == 'Set') {
               // Assuming 'Set' tag is manually added or we check itemType if implemented
               // For now, check flavorTags for 'Set' or 'セット'
               final isSet = item.hiddenSpecs.flavorTags.contains('セット') || 
                             item.hiddenSpecs.flavorTags.contains('Set') ||
                             item.displayData.name.contains('セット');
               if (!isSet) return false;
            } else {
               final matchesTag = item.hiddenSpecs.flavorTags.contains(filterTag);
               if (!matchesTag) return false;
            }
        }

        return true;
      }).toList();

      // 2. Then apply sort based on SortMode
      switch (sortMode) {
        case SortMode.newest:
          filtered.sort((a, b) => b.metadata.createdAt.compareTo(a.metadata.createdAt));
          break;
        case SortMode.oldest:
          filtered.sort((a, b) => a.metadata.createdAt.compareTo(b.metadata.createdAt));
          break;
        case SortMode.name:
          filtered.sort((a, b) => a.displayData.name.compareTo(b.displayData.name));
          break;
        case SortMode.custom:

          // Use Manual Sort Order
          return sortOrderAsync.when(
            data: (sortOrder) {
               if (sortOrder.isEmpty) {
                 // Default fallback if no custom order
                 filtered.sort((a, b) => b.metadata.createdAt.compareTo(a.metadata.createdAt));
                 return AsyncValue.data(filtered);
               }
    
               final orderMap = {for (var i = 0; i < sortOrder.length; i++) sortOrder[i]: i};
    
               filtered.sort((a, b) {
                 final idxA = orderMap[a.id];
                 final idxB = orderMap[b.id];
    
                 if (idxA != null && idxB != null) {
                   return idxA.compareTo(idxB);
                 } else if (idxA != null) {
                   return -1;
                 } else if (idxB != null) {
                   return 1;
                 } else {
                   return b.metadata.createdAt.compareTo(a.metadata.createdAt);
                 }
               });
               
               return AsyncValue.data(filtered);
            },
            loading: () => AsyncValue.data(filtered),
            error: (e, s) => AsyncValue.error(e, s),
          );
      }
      
      return AsyncValue.data(filtered);
    },
    loading: () => const AsyncValue.loading(),
    error: (e, s) => AsyncValue.error(e, s),
  );
});


// 4. Controller for Updating Order
class SakeOrderController extends Notifier<void> {
  @override
  void build() {}

  void updateOrder(List<SakeItem> newOrder) {
    final box = Hive.box('settings');
    final ids = newOrder.map((e) => e.id).toList();
    box.put('sake_sort_order', ids);
  }
}

final sakeOrderControllerProvider = NotifierProvider<SakeOrderController, void>(SakeOrderController.new);

// 5. All Items Provider (フィルタなし、全件取得用)
// ソムリエ診断など、フィルタリングせず全体の傾向を見たい場合に使用
final allSakeItemsProvider = Provider<AsyncValue<List<SakeItem>>>((ref) {
  final rawListAsync = ref.watch(rawSakeListItemsProvider);

  return rawListAsync.when(
    data: (rawList) {
      if (rawList.isEmpty) return const AsyncValue.data([]);

      // ソートのみ適用（新しい順）
      final sorted = List<SakeItem>.from(rawList);
      sorted.sort((a, b) => b.metadata.createdAt.compareTo(a.metadata.createdAt));

      return AsyncValue.data(sorted);
    },
    loading: () => const AsyncValue.loading(),
    error: (e, s) => AsyncValue.error(e, s),
  );
});

extension StreamStartWith<T> on Stream<T> {
  Stream<T> startWith(T initial) async* {
    yield initial;
    yield* this;
  }
}
