import 'dart:async';

import 'package:common_pub/logger.dart';
import 'package:common_pub/model/history_detail.dart';
import 'package:common_pub/ui/history_detail/trace_bar.dart';
import 'package:common_pub/ui/map_view/view_map_cp.dart';
import 'package:common_pub/ui/map_view/view_map_trace.dart';
import 'package:get/get.dart';

import '../../../service/map_watch.dart';

class UserDetail {
  var id = 0;
  var name = '';
  var history = <UserHistorySimple>[];
}

class UserHistorySimple {
  var gameId = 0;
  var routeName = '';
  var eventName = '';
  var isComplete = false;
  var startAt = DateTime.now();
  var duration = 0.seconds;
}

class UserInfo {
  var data = UserDetail();
  final isExpand = false.obs;
}

abstract class DataDetailController extends GetxController {
  MapWatch? get mapWatch => Get.find<MapWatchService>().instance;
  final userMap = <int, UserInfo>{}.obs;
  Iterable<UserInfo> get userList => userMap.values;
  final selectedDetailSimple = UserHistorySimple().obs;
  final selectedUserId = (-9).obs;
  final Rx<HistoryDetail?> selectedDetail = Rx(null);
  final showDetail = false.obs;
  final isCPExpand = true.obs;
  final traceBarController = TraceBarController();
  final viewMapTraceController = ViewMapTraceController();
  StreamSubscription<int?>? _subscriptionTrace;
  final selectedLoading = false.obs;
  final viewCPController = ViewMapCPController();

  @override
  void onInit() {
    super.onInit();
    _subscriptionTrace = traceBarController.cursorState.listen((p0) {
      viewMapTraceController.cursor = p0;
    });
    workFlush();
  }

  Future<List<UserDetail>> getUserList(int mapId);

  /// GameDetailV2Reply bytes
  Future<List<int>> getHistoryDetail(int gameId);

  Future<void> workFlush() async {
    while (!isClosed) {
      await flushData();
      await 1.seconds.delay();
    }
  }

  Future<void> flushData() async {
    final map = mapWatch;
    if (map == null) {
      return;
    }

    try {
      final list = await getUserList(map.id);
      for (final one in list) {
        final updated = userMap[one.id] ?? UserInfo();
        updated.data = one;
        userMap[one.id] = updated;
      }
    } catch (e) {
      error(e);
    }
  }

  void selectDetail(UserHistorySimple d, UserInfo user) async {
    selectedDetailSimple.value = d;
    selectedUserId.value = user.data.id;
    selectedLoading.value = true;
    try {
      final t = DateTime.now();
      final detailBytes = await getHistoryDetail(d.gameId);
      final data = GameDetailV2Reply.fromBuffer(detailBytes);
      final detail = HistoryDetail(data);

      final cost = DateTime.now().difference(t);
      info("api cost $cost");

      await detail.init(mapWatch!.plugMap.gameMap);
      final old = selectedDetail.value;
      selectedDetail.value = detail;
      debug('select: ${detail.data.gameId}');
      if (old != null) {
        old.dispose();
      }
    } finally {
      selectedLoading.value = false;
    }
  }

  @override
  void onClose() {
    super.onClose();
    _subscriptionTrace?.cancel();
  }
}
