import 'package:app_business/service/api.dart';
import 'package:track_common/model.dart';
import 'package:track_common/model/event_state.dart';
import 'package:track_common/service/map_watch.dart';

import '../generated/base.pb.dart' as pb;
import '../model/game_map.dart';

class MapWatchImpl extends MapWatch {
  MapWatchImpl({required super.id});

  ApiService get _api => Get.find();
  @override
  Future<List<EventInfo>> getEventList(int mapId) async {
    final r = await _api.stub
        .toUserDetailQueryV2(pb.ToUserDetailQueryRequestV2()..mapId = mapId);
    final eventList = <EventInfo>[];

    for (var one in r.list) {
      eventList.add(EventInfo()
        ..id = one.actId
        ..players = one.userList.map((e) => toAppPlayer(e)).toList());
    }
    return eventList;
  }

  PlayerInfo toAppPlayer(pb.ToOrienteerInGameInfo e) {
    final save = e.gameSaveInfo;
    final startAt = save.hasStartAt() ? save.startAt.toModel() : DateTime.now();
    final out = PlayerInfo()
      ..id = e.userId
      ..startAt = startAt
      ..distance = e.gpsInfo.distance.meter
      ..duration = Duration.zero
      ..positionHistory = e.gpsInfo.gameGpsInfos
          .map((e) => Position()
            ..latitude = e.latitude
            ..longitude = e.longitude
            ..altitude = e.altitude
            ..timestamp = e.gpsTime.toModel())
          .toList()
      ..heartRatePercent = e.otherInfo.heartRatePercent
      ..stepCount = e.otherInfo.stepNum
      ..cpListChecked = save.checkedSortedList.isEmpty
          ? []
          : save.checkedSortedList
              .map((e) => ControlPoint()
                ..isSuccess = e.isCheckSuccess
                ..intId = e.controlPointId.toInt64())
              .toList();

    if (save.hasStartAt()) {
      out.hrHistory = e.hrInfo.hrInfo
          .map((e) => HeartRate(
              startAt.add(Duration(milliseconds: e.timeStampMs.toInt())), e.hr))
          .toList();
      out.duration = DateTime.now().difference(startAt);
    }

    return out;
  }

  @override
  Future<EventInfoExt> getEventInfoExt(int id) async {
    final r = await _api.stub.toActionBasicQuery(IdRequest()..id = Int64(id));
    final event = EventInfoExt()
      ..name = r.actName
      ..cpAllCount = r.totalControlNum
      ..startAt = r.matchBt
      ..endAt = r.matchEt
      ..state = switch (r.state) {
        0 => EventState.idle,
        1 => EventState.start,
        _ => EventState.finish,
      };

    return event;
  }

  @override
  Future<PlayerInfoExt> getPlayerInfoExt(int eventId, int userId) async {
    final r = await _api.stub
        .toUserInActionBasicQuery(pb.ToUserInActionBasicQueryRequest()
          ..actId = eventId
          ..userId = userId);

    final player = PlayerInfoExt()
      ..name = r.baseInfo.name
      ..routeName = r.courseBaseInfo.courseName
      ..cpListWant = r.courseBaseInfo.controlPointSortedList
          .map((e) => e.toModel())
          .toList();

    for (var (i, cp) in player.cpListWant.indexed) {
      cp.sn = i.toString();
    }

    return player;
  }
}

class MapWatchServiceImpl extends MapWatchService {
  ApiService get _api => Get.find();
  @override
  Future<MapWatch> newInstanceByMap(MapInfo info) async {
    final r =
        await _api.stub.toMapDetailV2(pb.IdRequest()..id = Int64(info.id));

    final instance = MapWatchImpl(id: info.id)
      ..name = r.mapName
      ..plugMap.gameMap = r.zipImage.toGameMap();

    return instance;
  }
}
