import 'dart:async';
import 'dart:convert';
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:injectable/injectable.dart';
import 'package:location/base/base_controller.dart';
import 'package:location/data/bean/user_info.dart';
import 'package:location/data/repositories/track_repository.dart';
import 'package:location/sdk/map/map_helper.dart';
import 'package:lottie/lottie.dart';
import 'package:video_player/video_player.dart';
import '../../data/bean/stream_chat_origin_data.dart';
import '../../data/bean/track_daily_bean.dart';
import '../../resource/assets.gen.dart';
import '../../resource/string.gen.dart';
import '../../utils/http_handler.dart';
import '../../widget/gradually_print_text.dart';
import 'location_analyse_util.dart';

@injectable
class LocationAnalyseController extends BaseController
    with GetTickerProviderStateMixin {
  late final VideoPlayerController locaController;

  final RxBool _videoReady = RxBool(false);

  UserInfo? userInfo;
  TrackDailyBean? errorInfo;

  RxList<TrackDailyBean> errorAddr = RxList();
  final RxBool _isShowAnalyseAddr = RxBool(false);

  bool get isShowAnalyseAddr => _isShowAnalyseAddr.value;

  final RxBool _showAnalyseRemainContent = RxBool(false);

  bool get showAnalyseRemainContent => _showAnalyseRemainContent.value;

  bool get videoReady => _videoReady.value;

  StreamSubscription? _streamSubscription;

  final GraduallyController graduallyController = GraduallyController();

  final RxBool _isShowAnalyseResult = RxBool(false);

  bool get isShowAnalyseResult => _isShowAnalyseResult.value;

  final RxBool _isRequestedAnalyse = RxBool(false);

  bool get isRequestedAnalyse => _isRequestedAnalyse.value;

  bool _isRequestingStream = false;

  final RxnString _summaryError = RxnString();

  String? get summaryError => _summaryError.value;

  final Rxn<LottieDelegates> _keywordDelegates = Rxn<LottieDelegates>();

  LottieDelegates? get keywordDelegates => _keywordDelegates.value;

  final TrackRepository trackRepository;

  late AnimationController keywordLottieController =
      AnimationController(vsync: this);
  bool _keywordLottieReady = false;

  Timer? _loopTimer;

  Duration loopStart = const Duration(milliseconds: 0);
  Duration loopEnd = const Duration(milliseconds: 5032);

  LocationAnalyseController(this.trackRepository);

  @override
  void onInit() {
    super.onInit();
    _initArgs();
    _getKeyword();
    _getErrorAddr();

    graduallyController.setGraduallyFinishedListener(() {
      _isRequestingStream = false;
    });

    locaController = VideoPlayerController.asset(
      Assets.anim.locationAnalyseRobot,
    )
      ..setVolume(0.0)
      ..initialize().then((_) {
        _videoReady.value = true;
        _startMonitorLoop();
      }).catchError((error) {
        debugPrint('Error initializing video: $error');
      });
  }

  void _startMonitorLoop() {
    locaController.play();
    _loopTimer =
        Timer.periodic(const Duration(milliseconds: 100), (timer) async {
      final position = await locaController.position;
      if (position == null) return;
      if (position >= loopEnd) {
        locaController.seekTo(loopStart);
      }
    });
  }

  void _getErrorAddr() {
    trackRepository
        .trackDailyInterpret(
            startTime: errorInfo?.start,
            endTime: errorInfo?.end,
            userId: userInfo?.id)
        .then((list) {
      errorAddr.assignAll(list ?? []);
    });
  }

  void _getKeyword() {
    trackRepository
        .dailyKeyword(
            startTime: errorInfo?.start,
            endTime: errorInfo?.end,
            userId: userInfo?.id)
        .then((list) {
      //填充分析异常点到lottie占位中，有6个占位点，list如果小于则循环显示，如果超过6个，则随机6个选择，但不能重复出现
      if (list != null && list.isNotEmpty) {
        _keywordDelegates.value =
            LocationAnalyseUtil.convertKeywordDelegates(list);
      }
    });
  }

  void _initArgs() {
    final info = parameters?['userInfo'];
    if (info is UserInfo) {
      userInfo = info;
    }
    final errorInfo = parameters?['errorData'];
    if (errorInfo is TrackDailyBean) {
      this.errorInfo = errorInfo;
    }
  }

  void back() {
    Get.back();
  }

  void onTrackRefreshClick() {
    if (_isRequestingStream) {
      return;
    }
    _startMonitorLoop();
    _startKeywordLottieAnimation();
    _analyseErrorAddr();
  }

  String getErrorDistance(TrackDailyBean errorAddr) {
    final lastLocation = MapHelper.getLastLocation();
    if (lastLocation == null ||
        errorAddr.lat == null ||
        errorAddr.lng == null) {
      return StringName.unopenedPositioning;
    }
    final distance = MapUtil.calculateLineDistance(lastLocation.longitude,
        lastLocation.latitude, errorAddr.lng!, errorAddr.lat!);
    return MapUtil.format(distance);
  }

  void onAnalyseTextComplete() {
    _isShowAnalyseAddr.value = true;
    Future.delayed(Duration(milliseconds: 700), () {
      _showAnalyseRemainContent.value = true;
    });
  }

  void onAnalyseFinishComplete() {
    _isShowAnalyseResult.value = true;
    _analyseErrorAddr();
  }

  void _analyseErrorAddr() {
    //准备调用分析总结
    if (_isRequestingStream) {
      return;
    }

    _isRequestedAnalyse.value = false;
    _isRequestingStream = true;
    graduallyController.clear();
    _summaryError.value = null;

    trackRepository
        .streamDailyExceptionAnalyse(
            startTime: errorInfo?.start,
            endTime: errorInfo?.end,
            userId: userInfo?.id)
        .then((stream) {
      _streamSubscription?.cancel();
      _streamSubscription = 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();
        _setAnalyseSuccess();
      }, onError: (error) {
        _summaryError.value = "网络错误，请检查网络连接";
        debugPrint("error: $error");
        _isRequestedAnalyse.value = false;
        _isRequestingStream = false;
        debugPrintStack();
        _setAnalyseSuccess();
      });
    }).catchError((error) {
      _isRequestedAnalyse.value = false;
      _isRequestingStream = false;
      if (error is ServerErrorException) {
        final msg = error.message;
        if (msg == null) {
          _summaryError.value = error.message ?? "服务出错，请稍后再试";
        } else {
          graduallyController.append(msg);
          graduallyController.appendDone();
        }
        _setAnalyseSuccess();
      } else {
        _summaryError.value = "网络错误，请检查网络连接";
        debugPrint("error: $error");
        debugPrintStack();
      }
    });
  }

  void locationKeywordLottieLoad(LottieComposition composition) {
    _keywordLottieReady = true;
    keywordLottieController.duration = composition.duration;
    _startKeywordLottieAnimation();
  }

  void _startKeywordLottieAnimation() async {
    if (!_keywordLottieReady) {
      return;
    }
    await keywordLottieController.animateTo(0.84);
    keywordLottieController.repeat(min: 0, max: 0.84, reverse: true);
  }

  void _setAnalyseSuccess() async {
    _loopTimer?.cancel();
    if (_keywordLottieReady) {
      await keywordLottieController.animateTo(1);
    }
    _isRequestedAnalyse.value = true;
  }

  @override
  void onClose() {
    _loopTimer?.cancel();
    _streamSubscription?.cancel();
    keywordLottieController.dispose();
    super.onClose();
  }
}
