import 'package:result_monad/result_monad.dart';

import '../../models/circle_data.dart';
import '../../models/connection.dart';
import '../../models/exec_error.dart';
import '../interfaces/circles_repo_intf.dart';

class MemoryCirclesRepo implements ICirclesRepo {
  final _circlesForConnection = <String, List<CircleData>>{};
  final _connectionsForCircle = <String, Set<Connection>>{};
  final _myCircles = <CircleData>{};

  @override
  void clear() {
    _circlesForConnection.clear();
    _connectionsForCircle.clear();
    _myCircles.clear();
  }

  @override
  Result<List<CircleData>, ExecError> getCirclesForUser(String id) {
    if (!_circlesForConnection.containsKey(id)) {
      return Result.error(ExecError(
        type: ErrorType.notFound,
        message: '$id not a known user ID',
      ));
    }

    return Result.ok(_circlesForConnection[id]!);
  }

  @override
  List<CircleData> getMyCircles() {
    return _myCircles.toList();
  }

  @override
  Result<List<Connection>, ExecError> getCircleMembers(CircleData circle) {
    if (_connectionsForCircle.containsKey(circle.id)) {
      return Result.ok(_connectionsForCircle[circle.id]!.toList());
    }

    return buildErrorResult(
      type: ErrorType.notFound,
      message: 'Circle ${circle.id} not found',
    );
  }

  @override
  void clearMyCircles() {
    _myCircles.clear();
  }

  @override
  void addConnectionToCircle(CircleData circle, Connection connection) {
    _connectionsForCircle.putIfAbsent(circle.id, () => {}).add(connection);
    _circlesForConnection[connection.id]?.add(circle);
  }

  @override
  void addAllCircles(List<CircleData> circle) {
    _myCircles.addAll(circle);
  }

  @override
  bool updateConnectionCircleData(String id, List<CircleData> currentCircles) {
    _circlesForConnection[id] = currentCircles;
    return true;
  }

  @override
  void upsertCircle(CircleData circle) {
    _connectionsForCircle.putIfAbsent(circle.id, () => {});
    _myCircles.remove(circle);
    _myCircles.add(circle);
  }

  @override
  void deleteCircle(CircleData circle) {
    for (final conCircles in _circlesForConnection.values) {
      conCircles.remove(circle);
    }
    _connectionsForCircle.remove(circle.id);
    _myCircles.remove(circle);
  }
}
