import 'package:flutter/material.dart';
import 'package:async/async.dart';
import '../model/flood_station.dart';
import 'api.dart';

class FloodStationProvider extends ChangeNotifier {
  // since the getter and setter for the following two fields would be empty, they are publicly accessible
  FloodStation? selectedStation;
  bool filtered = false;

  List<FloodStation> _allStations = [];
  List<FloodStation> _filteredStations = [];
  CancelableOperation? _filteredStationsFuture;

  List<FloodStation> get allStations => _allStations;
  List<FloodStation> get filteredStations => _filteredStations;
  CancelableOperation? get filteredStationsFuture => _filteredStationsFuture;

  /// loads all stations in batches of 500 and notifies listeners with every loop except if [silent] = true
  /// this has lower performance than loading them all at once an shouldn't be used
  Future loadAllStationsInBatches({bool silent = false}) {
    int offset = 0;
    return Future.doWhile(() async {
      final stations = await Api.fetchStationsByRange(500, offset);
      if (stations.isNotEmpty) {
        _allStations.addAll(stations);
        if (!silent) {
          notifyListeners();
        }
        offset += 500;
        return true;
      } else {
        return false;
      }
    });
  }

  /// loads all flood stations and notifies listeners when done
  Future loadAllStations({bool silent = false}) {
    return Api.fetchAllStations().then(
      (value) {
        _allStations = value;
        if (!silent) {
          notifyListeners();
        }
      },
    );
  }

  /// loads all stations whose label contains [filter]
  Future loadFilteredStations(String filter, {bool silent = false}) {
    if (_filteredStationsFuture != null) {
      _filteredStationsFuture!.cancel();
    }
    final future = Api.fetchFilteredStations(filter);
    _filteredStationsFuture = CancelableOperation.fromFuture(future).then(
      (value) {
        _filteredStations = value;
        if (!silent) {
          notifyListeners();
        }
      },
    );
    return future;
  }

  /// cancels loading of filtered results.
  void cancelFilterLoading() {
    if (_filteredStationsFuture != null) {
      _filteredStationsFuture!.cancel();
    }
  }
}
