import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:get/get.dart';
import 'package:get/get_core/src/get_main.dart';
import 'package:location/base/base_controller.dart';
import 'package:location/data/bean/track_daily_bean.dart';
import 'package:location/data/consts/constants.dart';
import 'package:location/data/repositories/account_repository.dart'
    show AccountRepository;
import 'package:location/data/repositories/track_repository.dart';
import 'package:location/dialog/loading_dialog.dart';
import 'package:location/handler/error_handler.dart';
import 'package:location/module/analyse/location_analyse_page.dart';
import 'package:location/module/track/track_controller.dart';
import 'package:location/module/track/track_day_detail/time_proportion/pie_chat_data.dart';
import 'package:location/module/track/track_util.dart';
import 'package:location/resource/string.gen.dart';
import 'package:location/utils/async_util.dart';
import 'package:location/utils/common_expand.dart';
import 'package:location/utils/pair.dart';
import 'package:location/utils/toast_util.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../data/api/response/track_daily_summary_response.dart';
import '../../../data/bean/atmob_track_point.dart';
import '../../../data/bean/stream_chat_origin_data.dart';
import '../../../data/bean/track_days.dart';
import '../../../utils/http_handler.dart';
import '../../../widget/gradually_print_text.dart';
import '../track_status.dart';

class TrackDayDetailController extends BaseController {
  final TrackDays days;

  late TrackRepository trackRepository;
  late final AccountRepository accountRepository;
  final RxBool _trackNoData = RxBool(false);
  final RxList<TrackDailyBean> trackDailyList = RxList<TrackDailyBean>();

  final RxBool _isExpanded = RxBool(false);
  final RxBool _isRequested = RxBool(false);
  final RxBool _isHideExpand = RxBool(false);

  bool get isHideExpand => _isHideExpand.value;

  bool get isRequested => _isRequested.value;

  bool get isExpanded => _isExpanded.value;

  bool get trackNoData => _trackNoData.value;

  final Rxn<Pair<TrackExpandType, TrackDailyBean>> _expandSituation = Rxn();

  Pair<TrackExpandType, TrackDailyBean>? get expandSituation =>
      _expandSituation.value;

  final RxList<PieChatData> pieChatData = RxList<PieChatData>();
  int indexPieChatColor = 0;

  final TrackController trackController = Get.find<TrackController>();

  final RxBool _isShowGradually = RxBool(false);

  bool get isShowGradually => _isShowGradually.value;

  final Rxn<TrackDailySummaryResponse> _trackDailySummary = Rxn();

  TrackDailySummaryResponse? get trackDailySummary => _trackDailySummary.value;

  final GraduallyController graduallyController = GraduallyController();
  StreamSubscription? _streamChatSubscription;
  StreamSubscription? _currentTrackDaySubscription;

  final RxnString _summaryError = RxnString();

  RxDouble get _trackBottomHeight => trackController.trackBottomHeight;

  double get trackBottomHeight => _trackBottomHeight.value;

  CancelableFuture? requestTrackFuture;

  String? get summaryError => _summaryError.value;

  CancelableFuture? summaryFuture;

  //轨迹相关
  List<AtmobTrackPoint>? trackOriginPoints; //原始轨迹点
  List<LatLng> points = []; //根据停留情况合并的轨迹点
  List<Marker> markers = []; // 停留时间较长的标记点

  TrackDayDetailController(this.days, bool isExpand) {
    trackRepository = TrackRepository.getInstance();
    accountRepository = AccountRepository.getInstance();
    _isExpanded.value = isExpand;
  }

  @override
  void onReady() {
    _currentTrackDaySubscription =
        trackController.currentTrackDay.listen((dat) {
      if (dat == days) {
        _requestTrackData();
      }
    });
    _requestTrackDailySummary();
    _recordNumberTrajectoryViewed();
  }

  ///记录查看轨迹的次数
  void _recordNumberTrajectoryViewed() {
    if (accountRepository.memberStatusInfo.value?.trialed == true &&
        accountRepository.memberStatusInfo.value?.level == 20) {
      trackRepository.refreshMemberTrailTrack();
    }
  }

  _requestTrackData() {
    if (isRequested) {
      trackController.showMapTrack(points, markers);
      return;
    }
    requestTrackFuture?.cancel();
    CustomLoadingDialog.show(loadingTxt: StringName.trackLoadingTxt);
    requestTrackFuture = AsyncUtil.waitForAll(
        [_requestTrackHistoryPoints(), _requestTrackDaily()]);
    requestTrackFuture!.then((_) {
      //组装地图新的数据
      points.clear();
      markers.clear();
      for (int i = 0; i < trackDailyList.length; i++) {
        final bean = trackDailyList[i];
        double? markerLatitude;
        double? markerLongitude;
        if (bean.status == TrackStatus.stay) {
          //停留
          markerLatitude = bean.lat;
          markerLongitude = bean.lng;
          points.add(
              LatLng(latitude: markerLatitude, longitude: markerLongitude));
        } else if (bean.status == TrackStatus.moving) {
          //移动
          final movePoints = TrackUtil.getTrackMovePoints(
              trackOriginPoints, bean.start, bean.end);
          points.addAll(movePoints);
          continue;
        } else if (bean.status == TrackStatus.error) {
          continue;
        }

        MarkerType markerType;
        String? markerName;
        String? customAvatarUrl;
        if (i == 0) {
          //起点
          markerType = MarkerType.traceStartPoint;
        } else if (i == trackDailyList.length - 1) {
          //终点
          final userInfo = trackController.userInfo;
          markerName = userInfo?.getUserNickName();
          markerType = userInfo?.isMine == true
              ? MarkerType.traceEndMinePoint
              : MarkerType.traceEndMinePoint;
          customAvatarUrl = userInfo?.avatar;
        } else {
          markerType = MarkerType.tracePassingPoint;
        }
        markers.add(Marker(
            id: '${bean.start}',
            markerName: markerName ?? '',
            longitude: markerLongitude,
            latitude: markerLatitude,
            markerType: markerType,
            customAvatarUrl: customAvatarUrl));
      }
      if (markers.isNotEmpty &&
          (markers.last.markerType != MarkerType.traceEndMinePoint ||
              markers.last.markerType != MarkerType.traceEndFriendPoint)) {
        markers.last.markerType = trackController.userInfo?.isMine == true
            ? MarkerType.traceEndMinePoint
            : MarkerType.traceEndFriendPoint;
        markers.last.markerName =
            trackController.userInfo?.getUserNickName() ?? '';
        markers.last.customAvatarUrl = trackController.userInfo?.avatar;
      }
      //如果只有一个点，则添加一个起点和终点相同的点，绘制线需要2点
      if (points.length == 1) {
        points.add(points.first);
      }
      trackController.showMapTrack(points, markers);
    }).whenComplete(() {
      CustomLoadingDialog.hide();
    });
  }

  Future<void> _requestTrackHistoryPoints() {
    final userInfo = trackController.userInfo;
    trackOriginPoints = null;
    return Future.value().then((_) {
      if (userInfo?.virtual == true) {
        return trackRepository.queryVirtualTrack();
      } else {
        return trackRepository.queryTrack(
            startTime: days.start, endTime: days.end, userId: userInfo?.id);
      }
    }).then((data) {
      trackOriginPoints = data.trackPoints;
    });
  }

  void _requestTrackDailySummary() {
    summaryFuture?.cancel();
    summaryFuture = AsyncUtil.retry(
        () => _requestTrackSummary(), Duration(seconds: 2),
        maxRetry: 5);

    summaryFuture!.catchError((error) {
      ToastUtil.show(StringName.trackDetailDailySummaryGetFail);
    });
  }

  Future<TrackDailySummaryResponse> _requestTrackSummary() {
    return trackRepository
        .trackDailySummary(
            startTime: days.start,
            endTime: days.end,
            userId: trackController.userInfo?.id)
        .then((response) {
      _trackDailySummary.value = response;
      return response;
    });
  }

  Future<void> _requestTrackDaily() {
    _isRequested.value = false;
    return trackRepository
        .trackDailyQuery(
            startTime: days.start,
            endTime: days.end,
            userId: trackController.userInfo?.id)
        .then((list) {
      _isRequested.value = true;
      _trackNoData.value = (list == null || list.isEmpty == true);
      trackDailyList.assignAll(list ?? []);
      if (list != null && list.length == 1) {
        _isExpanded.value = true;
        _isHideExpand.value = true;
      }
      _dealPieChatData();
      _dealTrackExpandData();
    }).catchError((error) {
      _isRequested.value = false;
      ErrorHandler.toastError(error);
    });
  }

  void _dealPieChatData() {
    pieChatData.clear();
    final list = trackDailyList;
    if (list.isEmpty) {
      return;
    }
    indexPieChatColor = 0;
    int totalDuration = 0;
    final Map<String, PieChatData> addrMap = {};
    for (var bean in list) {
      if (bean.status == TrackStatus.error) {
        continue;
      }
      final addr = bean.addr;
      if (addr == null) {
        continue;
      }
      if (indexPieChatColor >= pieChatColors.length) {
        indexPieChatColor = 0;
      }
      totalDuration += bean.duration;
      if (addrMap.containsKey(addr)) {
        addrMap[addr]!.duration += bean.duration;
      } else {
        addrMap[addr] = PieChatData(
          address: addr,
          duration: bean.duration,
          color: pieChatColors[indexPieChatColor++],
        );
      }
    }
    for (var data in addrMap.values) {
      data.proportion =
          (data.duration / totalDuration * 100).toFormattedDouble(1);
    }
    pieChatData.addAll(addrMap.values.toList());
    //如果当数据为空，填入一个默认文案数据
    if (pieChatData.isEmpty) {
      PieChatData noStayData = PieChatData(
        address: StringName.trackNoStayData,
        duration: 0,
        proportion: 100,
        color: pieChatColors[0],
      );
      pieChatData.add(noStayData);
    }
  }

  void _dealTrackExpandData() {
    final list = trackDailyList;
    if (list.isNotEmpty && list.length > 1) {
      TrackExpandType? expandType;
      TrackDailyBean? expandBean;
      for (var i = 0; i < list.length; i++) {
        final bean = list[i];
        if (bean.status == TrackStatus.error) {
          expandType = TrackExpandType.error;
          expandBean = bean;
          break;
        } else if (bean.status == TrackStatus.stay) {
          if (expandBean == null) {
            expandType = TrackExpandType.stay;
            expandBean = bean;
          }
          continue;
        }
      }
      if (expandType != null && expandBean != null) {
        if (expandType == TrackExpandType.error &&
            list.indexOf(expandBean) == list.length - 1) {
          expandType = TrackExpandType.errorNow;
        } else if (expandType == TrackExpandType.stay &&
            list.indexOf(expandBean) == list.length - 1) {
          expandType = TrackExpandType.stayNow;
        }
        _expandSituation.value = Pair(expandType, expandBean);
      }
    }
  }

  void onTrackDetailFoldClick() {
    _isExpanded.value = !_isExpanded.value;
  }

  void checkGraduallyPrintTextVisible(double visibleFraction) {
    if (!isShowGradually && visibleFraction >= 0.3) {
      _isShowGradually.value = true;
      //流式获取轨迹情况
      _requestStreamTrackDaily();
    }
  }

  void _requestStreamTrackDaily() {
    graduallyController.dispose();
    _streamChatSubscription?.cancel();
    trackRepository
        .streamDailySummary(
            startTime: days.start,
            endTime: days.end,
            userId: trackController.userInfo?.id)
        .then((stream) {
      //
      graduallyController.setGraduallyFinishedListener(() {
        _trackDailySummary.value?.trackSituation =
            graduallyController.graduallyTxt;
        _trackDailySummary.refresh();
      });
      _streamChatSubscription = stream.listen((event) {
        try {
          Map<String, dynamic> json = jsonDecode(event.data);
          if (json.isEmpty) {
            return;
          }
          StreamChatOriginData data = StreamChatOriginData.fromJson(json);
          if (data.choices == null || data.choices!.isEmpty) {
            return;
          }
          Delta? delta = data.choices![0].delta;
          if (delta == null) {
            return;
          }
          graduallyController.append(delta.content ?? "");
        } catch (ignore) {}
      }, onDone: () {
        graduallyController.appendDone();
      }, onError: (error) {
        _summaryError.value = "网络错误，请检查网络连接";
        debugPrint("error: $error");
        debugPrintStack();
      });
    }).catchError((error) {
      if (error is ServerErrorException) {
        _summaryError.value = error.message ?? "服务出错，请稍后再试";
      } else {
        _summaryError.value = "网络错误，请检查网络连接";
        debugPrint("error: $error");
        debugPrintStack();
      }
    });
  }

  void onPhoneCallClick() async {
    final Uri uri = Uri.parse('tel:${trackController.userInfo?.phoneNumber}');
    if (await canLaunchUrl(uri)) {
      await launchUrl(uri);
    } else {
      ToastUtil.show(StringName.trackDailySkipCallPhoneFail);
    }
  }

  void onShareClick() async {
    final summary = _trackDailySummary.value;
    if (summary == null) {
      return;
    }
    if (summary.showTrackSituation == true &&
        (summary.trackSituation == null ||
            summary.trackSituation?.isEmpty == true)) {
      ToastUtil.show(StringName.trackStayShareAnalysis);
      return;
    }
    trackController.shareTrack(summary);
  }

  void onHistoryTrackItemClick(TrackDailyBean bean) {
    if (trackController.selectedTrackDailyBean == null ||
        trackController.selectedTrackDailyBean != bean) {
      if (bean.status == TrackStatus.stay) {
        //停留状态
        Marker selectMarker = Marker(
          id: Constants.tracePopupId,
          markerName: '',
          latitude: bean.lat,
          longitude: bean.lng,
          markerType: MarkerType.tracePopupPoint,
          tags: Platform.isIOS ? Popup(
            title: bean.addr ?? '',
            desc: TrackUtil.formatDurationFromMillis(bean.duration),
          ).toJson() : Popup(
            title: bean.addr ?? '',
            desc: TrackUtil.formatDurationFromMillis(bean.duration),
          ),
        );
        trackController.showSelectMarker(points, selectMarker);
      } else if (bean.status == TrackStatus.moving) {
        final movingPoints = TrackUtil.getTrackMovePoints(
            trackOriginPoints, bean.start, bean.end);
        trackController.showMovingTrack(movingPoints);
      } else if (bean.status == TrackStatus.error) {
        final errorPoints = TrackUtil.getTrackMovePoints(
            trackOriginPoints, bean.start, bean.end);
        if (errorPoints.isEmpty) {
          return;
        }
        Marker errorMarker = Marker(
            id: Constants.traceErrorId,
            markerName: '',
            latitude: errorPoints.first.latitude,
            longitude: errorPoints.first.longitude,
            markerType: MarkerType.trackErrorPoint);
        trackController.showTrackError(errorPoints, errorMarker);
      }
      trackController.selectedTrackDailyBean = bean;
    } else {
      //如果当前已经有选中的轨迹，则清除选中状态
      trackController.clearSelectMapMarker();
      trackController.selectedTrackDailyBean = null;
    }
  }

  void onAIAnalyseClick(TrackDailyBean bean) {
    final userInfo = trackController.userInfo;
    if (userInfo == null) {
      return;
    }
    LocationAnalysePage.start(errorData: bean, userInfo: userInfo);
  }

  @override
  void onClose() {
    super.onClose();
    _streamChatSubscription?.cancel();
    _currentTrackDaySubscription?.cancel();
    graduallyController.dispose();
    requestTrackFuture?.cancel();
  }
}
