import 'dart:async';

import 'package:flutter/material.dart';
import 'package:Emma_home/utils/class.dart';
//import 'dart:convert';
import 'package:Emma_home/main.dart';

const Duration fakeAPIDuration = Duration(milliseconds: 50);
const Duration debounceDuration = Duration(milliseconds: 50);

class Categories extends ChangeNotifier {
  // Private constructor
  Categories._privateConstructor();

  // Static instance
  static final Categories _instance = Categories._privateConstructor();

  // Static method to access the instance
  static Categories get instance => _instance;

  // Your singleton methods and properties
  static final List<Category> _categories = [
    Category(
      id: '1',
      title: 'Musik',
      imageUrl: 'assets/images/Musik.png',
      iconUrl: 'assets/images/Icons/Icon_Musik.png',
      color: const Color.fromARGB(255, 249, 171, 21), //FD4949 //Musik
      category: '34725c49-740b-45c5-8a51-7c742f92a621',
      textheight: 86,
      amount: 0,
    ),
    Category(
      id: '2',
      title: 'Nachtleben',
      imageUrl: 'assets/images/Nachtleben.png',
      iconUrl: 'assets/images/Icons/Icon_Nachtleben.png',
      color: const Color.fromARGB(255, 253, 73, 73), //FD4949 //Nachtleben
      category: '2d8c714e-3290-4d8c-8a95-e3b100ad8599',
      textheight: 86,
      amount: 0,
    ),
    Category(
      id: '3',
      title: 'Kunst & Kultur',
      imageUrl: 'assets/images/Kultur.png',
      iconUrl: 'assets/images/Icons/Icon_Kultur.png',
      color: const Color.fromARGB(255, 80, 168, 250), //50A8FA//Kunst
      category: '09d1f862-2b56-47af-8ee6-3c50056e3fa2',
      textheight: 58,
      amount: 0,
    ),
    Category(
      id: '4',
      title: 'Sport & Verein',
      imageUrl: 'assets/images/Sport.png',
      iconUrl: 'assets/images/Icons/Icon_Sport.png',
      color: const Color.fromARGB(255, 80, 240, 250), //50F0FA //Sport
      category: '15119876-9ff0-41e5-8fe5-c3675af5e054',
      textheight: 58,
      amount: 0,
    ),
    Category(
      id: '5',
      title: 'Gesundheit',
      imageUrl: 'assets/images/Gesundheit.png',
      iconUrl: 'assets/images/Icons/Icon_Gesundheit.png',
      color: const Color.fromARGB(255, 130, 73, 253), //8249FD //Gesundheit
      category: '4ad3ac2d-04fc-4aa1-afae-17ec7bfc1714',
      textheight: 86,
      amount: 0,
    ),
    Category(
      id: '6',
      title: 'Essen & Trinken',
      imageUrl: 'assets/images/Essen.png',
      iconUrl: 'assets/images/Icons/Icon_Essen.png',
      color: const Color.fromARGB(255, 253, 73, 73), //FD4949//Essen
      category: 'ef83c4d3-228a-44e1-8a5d-8b47d2dfc351',
      textheight: 58,
      amount: 0,
    ),
    Category(
      id: '7',
      title: 'Soziales',
      imageUrl: 'assets/images/Soziales.png',
      iconUrl: 'assets/images/Icons/Icon_Soziales.png',
      color: const Color.fromARGB(255, 255, 0, 199), //FF00C7//Essen
      category: '53a1782b-e07b-491d-b778-d99ef9cf57e2',
      textheight: 86,
      amount: 0,
    ),
    Category(
      id: '8',
      title: 'Familie',
      imageUrl: 'assets/images/Familie.png',
      iconUrl: 'assets/images/Icons/Icon_Familie.png',
      color: const Color.fromARGB(
          255, 66, 255, 0), //42FF00//Essen //HSL 104 100 50 100
      category: '30cb3481-c425-4068-9714-adc86df85d3f',
      textheight: 86,
      amount: 0,
    ),
  ];

  void addCategory(Category category) {
    category.add(category);
    notifyListeners();
  }

  void updateCategory(int index, Category updatedCategory) {
    if (index >= 0 && index < _categories.length) {
      _categories[index] = updatedCategory;
      notifyListeners();
    }
  }

  void removeCategory(int index) {
    if (index >= 0 && index < _categories.length) {
      _categories.removeAt(index);
      notifyListeners();
    }
  }

  Future<void> updateCategoryAmount(String cityName) async {
    try {
      for (var index = 0; index < _categories.length; index++) {
        //TODO: man müsste sicherstellen, dass die Main Category bei allen Events existent ist. Und dass in den jeweilige Subcategorien nicht die MainCatgeorie vorkommt. Erst dann kann das möglich sein.
        //müsste man auch in der Admin Page ermöglichen.
        final response = await supabase
            .from("events")
            .select(
                'id,name,main_category_id,location(name),event_category!inner(event_id)')
            .eq('event_category.category_id', _categories[index].category);
        var temp = (response.length);
        _categories[index].amount = temp;
        notifyListeners();
      }
      return;
    } catch (e) {
      throw Exception('Failed to fetch data: $e');
    }
    return;
  }

  // Method to get all items
  List<Category> get categories => List.unmodifiable(_categories);

  // Method to clear all items
  void clearItems() {
    _categories.clear();
  }

  // Method to get item count
  int get itemCount => _categories.length;
}

class SupabaseDataService {
  Future<List<Map<String, dynamic>>> fetchEvents(String category) async {
    try {
      final today = DateTime.now().toUtc().toString().split(' ')[0];
      final response = await supabase
          .from("events")
          .select(
              'id,name,description,detail,subheader,main_category_id,location(name),time!inner(*),event_category!inner(event_id)')
          .eq('event_category.category_id', category);
      //.gte('time.start_date', DateTime.now().toIso8601String().split('T')[0]) // Beginn des heutigen Tages
      //.lt('time.start_date', DateTime.now().add(Duration(days: 1)).toIso8601String().split('T')[0]); // Morgen;
      //select('id, name, cities(id, name)')
      //find all events mit Ort und zusatzinfos die die Kathegorie haben welche ausgewählt wurde am heutigen Tag dann kommender Tag usw.
      //final test = response[0]['time'][0]['start_date'];
      return (response as List).cast<Map<String, dynamic>>();
    } catch (e) {
      throw Exception('Failed to fetch data: $e');
    }
  }

  Future<Map<String, dynamic>> fetchSingleRecord(
      String tableName, String id) async {
    try {
      final response =
          await supabase.from(tableName).select().eq('id', id).single();

      return response;
    } catch (e) {
      throw Exception('Failed to fetch record: $e');
    }
  }
}
/* class _AsyncAutocomplete extends StatefulWidget {
  const _AsyncAutocomplete();

  @override
  State<_AsyncAutocomplete> createState() => _AsyncAutocompleteState();
}

class _AsyncAutocompleteState extends State<_AsyncAutocomplete> {
  // The query currently being searched for. If null, there is no pending
  // request.
  String? _currentQuery;

  // The most recent options received from the API.
  late Iterable<String> _lastOptions = <String>[];

  late final _Debounceable<Iterable<String>?, String> _debouncedSearch;

  // Whether to consider the fake network to be offline.
  bool _networkEnabled = true;

  // A network error was recieved on the most recent query.
  bool _networkError = false;

  // Calls the "remote" API to search with the given query. Returns null when
  // the call has been made obsolete.
  Future<Iterable<String>?> _search(String query) async {
    _currentQuery = query;

    late final Iterable<String> options;
    try {
      options = await _FakeAPI.search(_currentQuery!, _networkEnabled);
    } catch (error) {
      if (error is _NetworkException) {
        setState(() {
          _networkError = true;
        });
        return <String>[];
      }
      rethrow;
    }

    // If another search happened after this one, throw away these options.
    if (_currentQuery != query) {
      return null;
    }
    _currentQuery = null;

    return options;
  }
  
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    throw UnimplementedError();
  }
}
  // Mimics a remote API.
class _FakeAPI {
  static const List<String> _kOptions = <String>[
    'ingolstadt',
    'jesuitenstraße',
    'eiskeller',
  ];

  // Searches the options, but injects a fake "network" delay.
  static Future<Iterable<String>> search(
      String query, bool networkEnabled) async {
    await Future<void>.delayed(fakeAPIDuration); // Fake 1 second delay.
    if (!networkEnabled) {
      throw const _NetworkException();
    }
    if (query == '') {
      return const Iterable<String>.empty();
    }
    return _kOptions.where((String option) {
      return option.contains(query.toLowerCase());
    });
  }
}

typedef _Debounceable<S, T> = Future<S?> Function(T parameter);

/// Returns a new function that is a debounced version of the given function.
///
/// This means that the original function will be called only after no calls
/// have been made for the given Duration.
_Debounceable<S, T> _debounce<S, T>(_Debounceable<S?, T> function) {
  _DebounceTimer? debounceTimer;

  return (T parameter) async {
    if (debounceTimer != null && !debounceTimer!.isCompleted) {
      debounceTimer!.cancel();
    }
    debounceTimer = _DebounceTimer();
    try {
      await debounceTimer!.future;
    } catch (error) {
      if (error is _CancelException) {
        return null;
      }
      rethrow;
    }
    return function(parameter);
  };
}

// A wrapper around Timer used for debouncing.
class _DebounceTimer {
  _DebounceTimer() {
    _timer = Timer(debounceDuration, _onComplete);
  }

  late final Timer _timer;
  final Completer<void> _completer = Completer<void>();

  void _onComplete() {
    _completer.complete();
  }

  Future<void> get future => _completer.future;

  bool get isCompleted => _completer.isCompleted;

  void cancel() {
    _timer.cancel();
    _completer.completeError(const _CancelException());
  }
}

// An exception indicating that the timer was canceled.
class _CancelException implements Exception {
  const _CancelException();
}

// An exception indicating that a network request has failed.
class _NetworkException implements Exception {
  const _NetworkException();
}
  final _future = Supabase.instance.client
      .from('countries')
      .select();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder(
        future: _future,
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return const Center(child: CircularProgressIndicator());
          }
          final countries = snapshot.data!;
          return ListView.builder(
            itemCount: countries.length,
            itemBuilder: ((context, index) {
              final country = countries[index];
              return ListTile(
                title: Text(country['name']),
              );
            }),
          );
        },
      ),
    );
  } */
