import 'dart:async';
import 'package:built_collection/built_collection.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:invoiceninja_flutter/constants.dart';
import 'package:invoiceninja_flutter/data/models/models.dart';
import 'package:invoiceninja_flutter/redux/app/app_actions.dart';
import 'package:invoiceninja_flutter/redux/app/app_state.dart';
import 'package:invoiceninja_flutter/redux/settings/settings_actions.dart';
import 'package:invoiceninja_flutter/utils/completers.dart';
import 'package:invoiceninja_flutter/utils/localization.dart';
import 'package:invoiceninja_flutter/utils/platforms.dart';

class ViewStubList extends AbstractNavigatorAction implements PersistUI, StopLoading {
  ViewStubList({
    @required NavigatorState navigator,
    this.force = false,
  }) : super(navigator: navigator);

  final bool force;
}

class ViewStub extends AbstractNavigatorAction
    implements PersistUI, PersistPrefs {
  ViewStub({
    @required NavigatorState navigator,
    @required this.stubId,
    this.force = false,
  }) : super(navigator: navigator);

  final String stubId;
  final bool force;
}

class EditStub extends AbstractNavigatorAction
    implements PersistUI, PersistPrefs {
  EditStub(
      {@required this.stub,
      @required NavigatorState navigator,
      this.completer,
      this.cancelCompleter,
      this.force = false})
      : super(navigator: navigator);

  final StubEntity stub;
  final Completer completer;
  final Completer cancelCompleter;
  final bool force;
}

class UpdateStub implements PersistUI {
  UpdateStub(this.stub);

  final StubEntity stub;
}

class LoadStub {
  LoadStub({this.completer, this.stubId});

  final Completer completer;
  final String stubId;
}

class LoadStubActivity {
  LoadStubActivity({this.completer, this.stubId});

  final Completer completer;
  final String stubId;
}

class LoadStubs {
  LoadStubs({this.completer, this.force = false});

  final Completer completer;
  final bool force;
}

class LoadStubRequest implements StartLoading {}

class LoadStubFailure implements StopLoading {
  LoadStubFailure(this.error);

  final dynamic error;

  @override
  String toString() {
    return 'LoadStubFailure{error: $error}';
  }
}

class LoadStubSuccess implements StopLoading, PersistData {
  LoadStubSuccess(this.stub);

  final StubEntity stub;

  @override
  String toString() {
    return 'LoadStubSuccess{stub: $stub}';
  }
}

class LoadStubsRequest implements StartLoading {}

class LoadStubsFailure implements StopLoading {
  LoadStubsFailure(this.error);

  final dynamic error;

  @override
  String toString() {
    return 'LoadStubsFailure{error: $error}';
  }
}

class LoadStubsSuccess implements StopLoading, PersistData {
  LoadStubsSuccess(this.stubs);

  final BuiltList<StubEntity> stubs;

  @override
  String toString() {
    return 'LoadStubsSuccess{stubs: $stubs}';
  }
}


class SaveStubRequest implements StartSaving {
  SaveStubRequest({this.completer, this.stub});

  final Completer completer;
  final StubEntity stub;
}

class SaveStubSuccess implements StopSaving, PersistData, PersistUI {
  SaveStubSuccess(this.stub);

  final StubEntity stub;
}

class AddStubSuccess implements StopSaving, PersistData, PersistUI {
  AddStubSuccess(this.stub);

  final StubEntity stub;
}

class SaveStubFailure implements StopSaving {
  SaveStubFailure (this.error);

  final Object error;
}

class ArchiveStubsRequest implements StartSaving {
  ArchiveStubsRequest(this.completer, this.stubIds);

  final Completer completer;
  final List<String> stubIds;
}

class ArchiveStubsSuccess implements StopSaving, PersistData {
  ArchiveStubsSuccess(this.stubs);

  final List<StubEntity> stubs;
}

class ArchiveStubsFailure implements StopSaving {
  ArchiveStubsFailure(this.stubs);

  final List<StubEntity> stubs;
}

class DeleteStubsRequest implements StartSaving {
  DeleteStubsRequest(this.completer, this.stubIds);

  final Completer completer;
  final List<String> stubIds;
}

class DeleteStubsSuccess implements StopSaving, PersistData {
  DeleteStubsSuccess(this.stubs);

  final List<StubEntity> stubs;
}

class DeleteStubsFailure implements StopSaving {
  DeleteStubsFailure(this.stubs);

  final List<StubEntity> stubs;
}

class RestoreStubsRequest implements StartSaving {
  RestoreStubsRequest(this.completer, this.stubIds);

  final Completer completer;
  final List<String> stubIds;
}

class RestoreStubsSuccess implements StopSaving, PersistData {
  RestoreStubsSuccess(this.stubs);

  final List<StubEntity> stubs;
}

class RestoreStubsFailure implements StopSaving {
  RestoreStubsFailure(this.stubs);

  final List<StubEntity> stubs;
}


class FilterStubs implements PersistUI {
  FilterStubs(this.filter);

  final String filter;
}

class SortStubs implements PersistUI {
  SortStubs(this.field);

  final String field;
}

class FilterStubsByState implements PersistUI {
  FilterStubsByState(this.state);

  final EntityState state;
}

class FilterStubsByCustom1 implements PersistUI {
  FilterStubsByCustom1(this.value);

  final String value;
}

class FilterStubsByCustom2 implements PersistUI {
  FilterStubsByCustom2(this.value);

  final String value;
}

class FilterStubsByCustom3 implements PersistUI {
  FilterStubsByCustom3(this.value);

  final String value;
}

class FilterStubsByCustom4 implements PersistUI {
  FilterStubsByCustom4(this.value);

  final String value;
}

class FilterStubsByEntity implements PersistUI {
  FilterStubsByEntity({this.entityId, this.entityType});

  final String entityId;
  final EntityType entityType;
}


void handleStubAction(
    BuildContext context, List<BaseEntity> stubs, EntityAction action) {

  if (stubs.isEmpty) {
    return;
  }

  final store = StoreProvider.of<AppState>(context);
  final state = store.state;
  final CompanyEntity company = state.company;
  final localization = AppLocalization.of(context);
  final stub = stubs.first as StubEntity;
  final stubIds = stubs.map((stub) => stub.id).toList();

  switch (action) {
    case EntityAction.edit:
      editEntity(context: context, entity: stub);
      break;
    case EntityAction.restore:
      store.dispatch(RestoreStubsRequest(
          snackBarCompleter<Null>(context, localization.restoredStub), stubIds));
      break;
    case EntityAction.archive:
      store.dispatch(ArchiveStubsRequest(
          snackBarCompleter<Null>(context, localization.archivedStub), stubIds));
      break;
    case EntityAction.delete:
      store.dispatch(DeleteStubsRequest(
          snackBarCompleter<Null>(context, localization.deletedStub), stubIds));
      break;
    case EntityAction.toggleMultiselect:
      if (!store.state.stubListState.isInMultiselect()) {
        store.dispatch(StartStubMultiselect());
      }

      if (stubs.isEmpty) {
        break;
      }

      for (final stub in stubs) {
        if (!store.state.stubListState.isSelected(stub.id)) {
          store.dispatch(
              AddToStubMultiselect(entity: stub));
        } else {
          store.dispatch(
              RemoveFromStubMultiselect(entity: stub));
        }
      }
      break;
  }
}

class StartStubMultiselect {
  StartStubMultiselect();
}

class AddToStubMultiselect {
  AddToStubMultiselect({@required this.entity});

  final BaseEntity entity;
}

class RemoveFromStubMultiselect {
  RemoveFromStubMultiselect({@required this.entity});

  final BaseEntity entity;
}

class ClearStubMultiselect {
  ClearStubMultiselect();
}
