import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart';
import 'package:location/base/app_base_request.dart';
import 'package:location/data/api/atmob_api.dart';
import 'package:location/data/api/atmob_stream_api.dart';
import '../../base/base_response.dart';
import '../../di/get_it.dart';
import '../../utils/http_handler.dart';
import '../../utils/sse_parse_util.dart';
import '../api/request/query_track_request.dart';
import '../api/request/track_daily_action_request.dart';
import '../api/response/location_track_days_response.dart';
import '../api/response/query_track_response.dart';
import '../api/response/track_daily_action_response.dart';
import '../api/response/track_daily_dialogs_response.dart';
import '../api/response/track_daily_summary_response.dart';
import '../bean/track_daily_bean.dart';
import '../bean/track_days.dart';

@lazySingleton
class TrackRepository {
  final AtmobApi atmobApi;
  final AtmobStreamApi streamApi;

  List<TrackDays>? days;

  TrackRepository(this.atmobApi, this.streamApi);

  static TrackRepository getInstance() {
    return getIt.get<TrackRepository>();
  }

  Future<QueryTrackResponse> queryVirtualTrack() {
    return atmobApi
        .queryVirtualTrack(AppBaseRequest())
        .then(HttpHandler.handle(true));
  }

  Future<QueryTrackResponse> queryTrack(
      {required int? startTime,
      required int? endTime,
      required String? userId}) {
    return atmobApi
        .queryTrack(
            QueryTrackRequest(
                startTime: startTime, endTime: endTime, userId: userId),
            RequestOptions(
                receiveTimeout: Duration(seconds: 30),
                connectTimeout: Duration(minutes: 2)))
        .then(HttpHandler.handle(true));
  }

  ///试用期间上报查看轨迹次数
  Future<void> refreshMemberTrailTrack() {
    return atmobApi
        .memberTrailTrack(AppBaseRequest())
        .then(HttpHandler.handle(true));
  }

  Future<List<TrackDays>> getLocationTrackDays() async {
    if (days == null || days?.isEmpty == true) {
      final response = await _locationTrackDays();
      return response.days;
    } else {
      return days!;
    }
  }

  Future<LocationTrackDaysResponse> _locationTrackDays() {
    return atmobApi
        .locationTrackDays(AppBaseRequest())
        .then(HttpHandler.handle(false))
        .then((response) {
      days = response.days;
      return response;
    });
  }

  Future<List<TrackDailyBean>?> trackDailyQuery(
      {required int? startTime,
      required int? endTime,
      required String? userId}) {
    return atmobApi
        .trackDailyQuery(
            QueryTrackRequest(
                startTime: startTime, endTime: endTime, userId: userId),
            RequestOptions(
                receiveTimeout: Duration(seconds: 30),
                connectTimeout: Duration(minutes: 2)))
        .then(HttpHandler.handle(true))
        .then((response) {
      return response.trackDailyList;
    });
  }

  ///每日轨迹弹框报告-中台
  Future<TrackDailyDialogsResponse> locationTrackDailyDialogs() {
    return atmobApi
        .locationTrackDailyDialogs(AppBaseRequest())
        .then(HttpHandler.handle(true))
        .then((response) {
      return response;
    });
  }

  Future<TrackDailySummaryResponse> trackDailySummary(
      {required int? startTime,
      required int? endTime,
      required String? userId}) {
    return atmobApi
        .trackDailySummary(
            QueryTrackRequest(
                startTime: startTime, endTime: endTime, userId: userId),
            RequestOptions(
                receiveTimeout: Duration(seconds: 30),
                connectTimeout: Duration(minutes: 2)))
        .then(HttpHandler.handle(true));
  }

  Future<TrackDailyActionResponse> trackDailyAction(String? userId) {
    return atmobApi
        .trackDailyAction(
            TrackDailyActionRequest(userId),
            RequestOptions(
                receiveTimeout: Duration(seconds: 30),
                connectTimeout: Duration(minutes: 2)))
        .then(HttpHandler.handle(true));
  }

  Future<Stream<Message>> streamDailySummary(
      {required int? startTime,
      required int? endTime,
      required String? userId}) {
    return streamApi
        .dailySummary(QueryTrackRequest(
            startTime: startTime, endTime: endTime, userId: userId))
        .then((response) async {
      List<String>? contentType = response.headers['Content-Type'];
      if (contentType != null) {
        for (var value in contentType) {
          if (value.contains('text/event-stream')) {
            return response.stream;
          } else if (value.contains('application/json')) {
            BaseResponse<String> baseResponse = BaseResponse.fromJson(
                jsonDecode(await response.stream
                    .map((bytes) => utf8.decoder.convert(bytes))
                    .toList()
                    .then((value) => value.join())),
                (json) => json as String);
            throw ServerErrorException(baseResponse.code, baseResponse.message);
          }
        }
      }
      throw Exception('Invalid content type');
    }).then((stream) => SSEParseUtil.parse(stream));
  }

  Future<List<String>?> dailyKeyword(
      {required int? startTime,
      required int? endTime,
      required String? userId}) {
    return atmobApi
        .dailyKeyword(QueryTrackRequest(
            startTime: startTime, endTime: endTime, userId: userId))
        .then(HttpHandler.handle(true))
        .then((response) => response.list);
  }

  Future<List<TrackDailyBean>?> trackDailyInterpret(
      {required int? startTime,
      required int? endTime,
      required String? userId}) {
    return atmobApi
        .trackDailyInterpret(QueryTrackRequest(
            startTime: startTime, endTime: endTime, userId: userId))
        .then(HttpHandler.handle(true))
        .then((response) => response.list);
  }

  Future<Stream<Message>> streamDailyExceptionAnalyse(
      {required int? startTime,
      required int? endTime,
      required String? userId}) {
    return streamApi
        .dailyExceptionAnalyse(QueryTrackRequest(
            startTime: startTime, endTime: endTime, userId: userId))
        .then((response) async {
      List<String>? contentType = response.headers['Content-Type'];
      if (contentType != null) {
        for (var value in contentType) {
          if (value.contains('text/event-stream')) {
            return response.stream;
          } else if (value.contains('application/json')) {
            BaseResponse<String> baseResponse = BaseResponse.fromJson(
                jsonDecode(await response.stream
                    .map((bytes) => utf8.decoder.convert(bytes))
                    .toList()
                    .then((value) => value.join())),
                (json) => json as String);
            throw ServerErrorException(baseResponse.code, baseResponse.message);
          }
        }
      }
      throw Exception('Invalid content type');
    }).then((stream) => SSEParseUtil.parse(stream));
  }
}
