import 'dart:async';
import 'dart:math';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:qhd_prevention/customWidget/remote_file_page.dart';
import 'package:qhd_prevention/pages/home/study/take_exam_page.dart';
import 'package:qhd_prevention/pages/home/study/study_practise_page.dart';
import 'package:qhd_prevention/pages/my_appbar.dart';
import 'package:qhd_prevention/customWidget/custom_alert_dialog.dart';
import 'package:qhd_prevention/customWidget/custom_button.dart';
import 'package:qhd_prevention/http/ApiService.dart';
import 'package:qhd_prevention/tools/tools.dart';
import 'package:video_player/video_player.dart';
import 'package:wakelock_plus/wakelock_plus.dart';

import '../../../customWidget/toast_util.dart';
import '../../../customWidget/video_player_widget.dart';
import 'face_ecognition_page.dart';

enum TakeExamType { video_study, strengththen, list }

class StudyDetailPage extends StatefulWidget {
  final Map studyDetailDetail;
  final String studentId;

  const StudyDetailPage(this.studyDetailDetail, this.studentId, {super.key});

  @override
  State<StudyDetailPage> createState() => _StudyDetailPageState();
}

class _StudyDetailPageState extends State<StudyDetailPage>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;
  Map<String, dynamic>? _info;
  List<dynamic> _videoList = [];
  bool _loading = true;

  // player controller 提取出来
  VideoPlayerController? _videoController;
  String _videoCoverUrl = '';

  Timer? _faceTimer;
  late int _faceTime;
  late String _classId;
  late String _classCurriculumId;

  Map<String, dynamic>? _currentVideoData;
  int _currentFirstIndex = 0;
  int _currentNodeIndex = 0;
  bool _hasNodes = false;
  Duration _lastReported = Duration.zero;

  // 上报控制相关字段
  bool _endReported = false; // 确保最终结束上报只执行一次
  Future<void>? _ongoingSubmit; // 用于串行化提交请求
  final int _uploadIntervalSeconds = 1; // 周期性上报间隔（秒）

  @override
  void initState() {
    super.initState();
    WakelockPlus.enable();
    _classId = widget.studyDetailDetail['CLASS_ID'] ?? '';
    _classCurriculumId = widget.studyDetailDetail['CLASSCURRICULUM_ID'] ?? '';
    _tabController = TabController(length: 2, vsync: this);
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _showFaceIntro();
      _loadData();
    });
  }

  @override
  void dispose() {
    _tabController.dispose();
    WakelockPlus.disable();

    // 最佳努力：让未完成的提交完成（非阻塞）
    if (_ongoingSubmit != null) {
      _ongoingSubmit!.whenComplete(() {});
    }

    try {
      _videoController?.removeListener(_onTimeUpdate);
    } catch (_) {}
    try {
      _videoController?.dispose();
    } catch (_) {}
    _videoController = null;

    _faceTimer?.cancel();
    super.dispose();
  }

  Future<void> _showFaceIntro() async {
    final ok = await CustomAlertDialog.showConfirm(
      context,
      title: '温馨提示',
      content: '重要提醒：尊敬的用户，根据规定我们会在您学习过程中多次进行人脸识别认证，为了保护您的隐私请您在摄像设备视野内确保衣冠整齐。',
      cancelText: '取消',
      confirmText: '同意并继续',
    );
    if (ok) {}
  }

  Future<void> _loadData() async {
    try {
      final res = await ApiService.getStudyDetailList(
        _classId,
        _classCurriculumId,
        widget.studentId,
      );
      final pd = res['pd'] ?? {};
      _faceTime = int.tryParse(pd['FACE_TIME']?.toString() ?? '10') ?? 10;
      _videoList = List.from(pd['VIDEOLIST'] ?? []);
      // set initial face time

      // compute percent
      for (var item in _videoList) {
        if (item['nodes'] is List && (item['nodes'] as List).isNotEmpty) {
          for (var node in item['nodes']) {
            node['percent'] = _calcPercentStr(
              playCount: node['PLAYCOUNT'],
              resourceTime: node['RESOURCETIME'],
              videoTime: node['VIDEOTIME'],
            );
          }
        } else {
          item['percent'] = _calcPercentStr(
            playCount: item['PLAYCOUNT'],
            resourceTime: item['RESOURCETIME'],
            videoTime: item['VIDEOTIME'],
          );
        }
      }
      setState(() {
        _info = pd;
        _loading = false;
      });
    } catch (_) {
      setState(() => _loading = false);
    }
  }

  String _calcPercentStr({
    required dynamic playCount,
    required dynamic resourceTime,
    required dynamic videoTime,
  }) {
    final seen = int.tryParse('$playCount') ?? 0;
    if (seen > 0) return '100%';
    final resT = double.tryParse('$resourceTime') ?? 0.0;
    final vidT = double.tryParse('$videoTime') ?? 0.0;
    if (vidT == 0) return '0%';
    final pct = ((resT / vidT) * 100).clamp(0.0, 100.0).toStringAsFixed(0);
    return '$pct%';
  }

  Future<void> _onVideoTap(
    Map<String, dynamic> data,
    bool hasNodes,
    int fi,
    int ni,
  ) async {
    // 后端清除人脸计时
    await ApiService.fnClearUserFaceTime();
    _faceTimer?.cancel();
    if (_currentVideoData != null && _lastReported > Duration.zero) {
      await _submitPlayTime(end: false, seconds: _lastReported.inSeconds);
    }
    _lastReported = Duration.zero;

    _currentVideoData = data;
    _hasNodes = hasNodes;
    _currentFirstIndex = fi;
    _currentNodeIndex = ni;

    // 暂停已有播放器
    _videoController?.pause();

    await _navigateFaceIfNeeded(() async {
      if ((data['IS_VIDEO'] ?? 0) == 1) {
        // 文档
        if (data['VIDEOFILES'] != null) {
          _videoController?.pause();
          await pushPage(
            RemoteFilePage(
              fileUrl: ApiService.baseImgPath + data['VIDEOFILES'],
              countdownSeconds: 10,
            ),
            context,
          );
          await _submitPlayTime(
            end: true,
            seconds: int.parse(data['VIDEOTIME'] ?? '0'),
          );
        } else {
          ScaffoldMessenger.of(
            context,
          ).showSnackBar(const SnackBar(content: Text('课件文件资源已失效，请联系管理员')));
        }
      } else {
        // 视频
        await _getVideoPlayInfo(data['VIDEOCOURSEWARE_ID']);
        _startFaceTimer();
      }
    });
  }

  Future<void> _navigateFaceIfNeeded(FutureOr<void> Function() onPass) async {
    if (_info?['ISFACE'] == '1') {
      LoadingDialogHelper.show();
      final resData = await ApiService.fnGetUserFace();
      LoadingDialogHelper.hide();
      final pd_data = resData['pd'];
      if (FormUtils.hasValue(pd_data, 'USERAVATARURL')) {
        final passed = await pushPage<bool>(
          FaceRecognitionPage(studentId: widget.studentId, mode: FaceMode.auto),
          context,
        );
        if (passed == true) {
          await ApiService.fnSetUserFaceTime(_faceTime);
          await onPass();
        } else {
          ToastUtil.showError(context, '人脸验证未通过，无法继续');
        }
      } else {
        final ok = await CustomAlertDialog.showConfirm(
          context,
          title: '温馨提示',
          content: '您当前还未进行人脸认证，请先进行认证',
          cancelText: '取消',
        );
        if (ok) {
          await pushPage(
            const FaceRecognitionPage(studentId: '', mode: FaceMode.manual),
            context,
          );
        }

      }
    } else {
      await onPass();
    }
  }

  Future<void> _getVideoPlayInfo(String vidId) async {
    final res = await ApiService.fnGetVideoPlayInfo(vidId);
    final url = res['videoList']?[0]?['playURL'] ?? '';
    _videoCoverUrl = res['videoBase']?['coverURL'] ?? '';

    final prog = await ApiService.fnGetVideoPlayProgress(
      vidId,
      _currentVideoData!['CURRICULUM_ID'],
      _classId,
      widget.studentId,
    );

    final raw = prog['pd']?['RESOURCETIME'];
    final seen =
        (() {
          if (raw == null) return 0;
          // 如果本身就是数字
          if (raw is num) return raw.toInt();
          // 否则转成字符串再 parse
          final s = raw.toString();
          return (double.tryParse(s) ?? 0.0).toInt();
        })();

    // 先销毁旧 controller
    try {
      _videoController?.removeListener(_onTimeUpdate);
    } catch (_) {}
    try {
      _videoController?.dispose();
    } catch (_) {}
    _videoController = null;

    // 创建新 controller
    _videoController = VideoPlayerController.networkUrl(Uri.parse(url));
    await _videoController!.initialize();

    // 新增：为新视频重置上报相关标志
    _endReported = false;
    _lastReported = Duration.zero;
    _ongoingSubmit = null;

    setState(() {});

    // 直接从上次播放点 seek，并立即播放
    _videoController!
      ..seekTo(Duration(seconds: seen))
      ..play()
      ..addListener(_onTimeUpdate);
  }

  // 改进版本的 _onTimeUpdate，包含周期性上报 + 接近结束时的最终上报
  void _onTimeUpdate() {
    if (_videoController == null) return;
    final val = _videoController!.value;

    if (!val.isInitialized) return;
    final pos = val.position;
    final dur = val.duration;

    // 周期性上报：每隔 _uploadIntervalSeconds 秒上报一次
    final secondsSinceLast = (pos - _lastReported).inSeconds;
    if (secondsSinceLast >= _uploadIntervalSeconds && !_endReported) {
      _lastReported = pos;
      // 串行上报：通过 _ongoingSubmit 链式调用来保证顺序
      _ongoingSubmit = (_ongoingSubmit ?? Future.value())
          .then((_) {
            return _submitPlayTime(end: false, seconds: pos.inSeconds);
          })
          .whenComplete(() {
            // 完成后清理引用
            _ongoingSubmit = null;
          });
    }

    // 接近结束的检测，容差 800ms，触发一次最终结束上报
    if (dur != null && dur.inMilliseconds > 0) {
      final remainingMs = dur.inMilliseconds - pos.inMilliseconds;
      final endedOrClose = remainingMs <= 800;
      if (endedOrClose && !_endReported) {
        _endReported = true;
        final finalSeconds = (dur.inMilliseconds / 1000.0).ceil();
        _ongoingSubmit = (_ongoingSubmit ?? Future.value())
            .then((_) async {
              await _submitPlayTime(end: true, seconds: finalSeconds);
            })
            .whenComplete(() {
              _ongoingSubmit = null;
              // 最终上报完成后尝试退出顶层 route（退出全屏）
              _exitTopRouteIfPresent();
            });

        ApiService.fnClearUserFaceTime();
        _faceTimer?.cancel();
      }
    }
  }

  Future<void> _submitPlayTime({
    required bool end,
    required int seconds,
  }) async {
    if (_currentVideoData == null) return;

    // 如果已经上报结束并且当前不是结束上报，则跳过非结束上报
    if (_endReported && !end) return;

    Map data = {
      'VIDEOCOURSEWARE_ID': _currentVideoData!['VIDEOCOURSEWARE_ID'] ?? '',
      'CURRICULUM_ID': _currentVideoData!['CURRICULUM_ID'] ?? '',
      'CHAPTER_ID': _currentVideoData!['CHAPTER_ID'] ?? '',
      'RESOURCETIME': seconds,
      'IS_END': end ? '1' : '0',
      'CLASS_ID': _classId,
      'CLASSCURRICULUM_ID': _classCurriculumId,
      'STUDENT_ID': widget.studentId,
      'loading': false,
    };

    const int maxRetries = 2;
    int attempt = 0;
    while (true) {
      attempt++;
      try {
        final resData = await ApiService.fnSubmitPlayTime(data);
        final pd = resData['pd'] ?? {};

        // 解析后端返回的 RESOURCETIME（可能是数字或字符串）
        final resTraw = pd['RESOURCETIME'];
        final resT =
            (resTraw is num)
                ? resTraw.toDouble()
                : double.tryParse('$resTraw') ?? seconds.toDouble();

        // 从当前视频数据中安全解析 videoTime
        final videoTimeRaw = _currentVideoData!['VIDEOTIME'];
        final videoTime =
            (videoTimeRaw is String)
                ? double.tryParse(videoTimeRaw) ?? 1.0
                : (videoTimeRaw is num ? videoTimeRaw.toDouble() : 1.0);

        final comp = pd['PLAYCOUNT'] != null && pd['PLAYCOUNT'] > 0;

        final pctDouble =
            comp ? 100.0 : ((resT / (videoTime > 0 ? videoTime : 1.0)) * 100.0);
        final pct = (pctDouble.clamp(0.00, 100.00) * 100).round() / 100;
        final str = '${pct}%';

        if (mounted) {
          setState(() {
            if (_hasNodes) {
              _videoList[_currentFirstIndex]['nodes'][_currentNodeIndex]['percent'] =
                  str;
            } else {
              _videoList[_currentFirstIndex]['percent'] = str;
            }
          });
        }

        // 如果是结束上报且后端标注可考试，则弹窗处理
        if (end && pd['CANEXAM'] == '1') {
          _videoController?.pause();

          final ok = await CustomAlertDialog.showConfirm(
            context,
            title: '温馨提示',
            content: '当前任务内所有课程均已学完，是否直接参加考试？',
            cancelText: '否',
            confirmText: '是',
          );
          if (ok) {
            _startExam(resData);
          }
        }

        break; // 成功 -> 退出重试循环
      } catch (e, st) {
        debugPrint('submitPlayTime failed attempt $attempt: $e\n$st');
        if (attempt > maxRetries) {
          // 超过重试次数后放弃（避免无限重试）
          break;
        }
        await Future.delayed(Duration(milliseconds: 500 * attempt));
      }
    }
  }

  /// 开始考试
  Future<void> _startExam(Map resData) async {
    Map pd = resData['pd'] ?? {};
    Map paper = resData['paper'] ?? {};
    setState(() {
      _loading = true;
    });
    final arguments = {
      'STAGEEXAMPAPERINPUT_ID': paper['STAGEEXAMPAPERINPUT_ID'] ?? '',
      'STAGEEXAMPAPER_ID': paper['STAGEEXAMPAPER_ID'] ?? '',
      'CLASS_ID': _classId,
      'POST_ID': pd['POST_ID'] ?? '',
      'STUDENT_ID': widget.studentId,
      'NUMBEROFEXAMS': pd['NUMBEROFEXAMS'] ?? '',
    };
    print('--_startExam data---$arguments');

    final data = await ApiService.getStartExam(arguments);
    setState(() {
      _loading = false;
    });
    if (data['result'] == 'success') {
      pushPage(
        TakeExamPage(
          examInfo: {
            'CLASS_ID': _classId,
            'POST_ID': pd['POST_ID'] ?? '',
            'STUDENT_ID': widget.studentId,
            'STRENGTHEN_PAPER_QUESTION_ID':
                paper['STAGEEXAMPAPERINPUT_ID'] ?? '',
            ...data,
          },
          examType: TakeExamType.video_study,
        ),
        context,
      );
    } else {
      ToastUtil.showError(context, '请求错误');
    }
  }

  void _exitTopRouteIfPresent() {
    final route = ModalRoute.of(context);
    if (route == null) return;
    // 当当前路由不是最上层时，说明有别的 route 在上面（通常是全屏播放器）
    if (!route.isCurrent) {
      // 只尝试 pop 一次（安全）
      try {
        Navigator.of(context).maybePop();
      } catch (_) {
        // 忽略异常
      }
    }
  }

  void _startFaceTimer() {
    _faceTimer = Timer.periodic(Duration(seconds: _faceTime), (_) async {
      final res = await ApiService.fnGetUserFaceTime();
      final isPlaying = _videoController?.value.isPlaying == true;
      final isVideo = _currentVideoData?['IS_VIDEO'] == 0;
      final needAuth = FormUtils.hasValue(res, 'data');

      if (isPlaying && isVideo && !needAuth) {
        _exitTopRouteIfPresent();
        _videoController!.pause();
        _videoController!.removeListener(_onTimeUpdate);
        await _showFaceAuthOnce();
      }
    });
  }

  Future<void> _showFaceAuthOnce() async {
    // 先 cancel 定时器，避免跳转过程中再次触发
    _faceTimer?.cancel();
    _faceTimer = null;

    final passed = await pushPage<bool>(
      FaceRecognitionPage(studentId: widget.studentId, mode: FaceMode.auto),
      context,
    );

    if (passed == true) {
      await ApiService.fnSetUserFaceTime(_faceTime);
      // 认证通过后 —— 恢复播放、重新添加 listener，并更新上报基准
      try {
        // 如果 controller 还存在且已初始化
        if (_videoController != null && _videoController!.value.isInitialized) {
          // 先确保 listener 没有重复添加
          try {
            _videoController!.removeListener(_onTimeUpdate);
          } catch (_) {}

          // 更新上报基准，避免立即触发一次短时间内的重复上报
          try {
            final currentPos = _videoController!.value.position;
            _lastReported = currentPos;
            debugPrint('Face auth passed — resetting _lastReported to $currentPos');
          } catch (_) {
            _lastReported = Duration.zero;
          }

          // 恢复播放并绑定 listener（保证周期性进度上报恢复）
          await _videoController!.play();
          _videoController!.addListener(_onTimeUpdate);
        } else {
          // 如果 controller 为空或未初始化，仅尝试更新 UI
          debugPrint('Face auth passed but _videoController is null or not initialized');
        }
        setState(() {});
      } catch (e, st) {
        debugPrint('Error resuming playback after face auth: $e\n$st');
      }
      // 恢复人脸验证计时器
      _startFaceTimer();
    } else {
      ToastUtil.showError(context, '人脸验证未通过，无法继续');
      if (_videoController != null) {
        try {
          _videoController?.removeListener(_onTimeUpdate);
        } catch (_) {}
        try {
          _videoController?.dispose();
        } catch (_) {}
        _videoController = null;
      }
      _faceTimer?.cancel();
      setState(() {
      });
    }
  }


  Widget _buildVideoOrCover(double containerW, double containerH) {
    final c = _videoController;
    if (c != null && c.value.isInitialized) {
      return VideoPlayerWidget(
        allowSeek: false,
        controller: _videoController,
        coverUrl:
            _videoCoverUrl.isNotEmpty
                ? ApiService.baseImgPath + _videoCoverUrl
                : ApiService.baseImgPath + (_info?['COVERPATH'] ?? ''),
        aspectRatio: _videoController?.value.aspectRatio ?? 16 / 9,
      );
    } else {
      // controller 被销毁或未初始化，显示封面
      return Image.network(
        '${ApiService.baseImgPath}${_info?['COVERPATH'] ?? ''}',
        fit: BoxFit.fill,
        width: containerW,
        height: containerH,
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_loading) {
      return Scaffold(
        appBar: MyAppbar(title: '学习详情'),
        body: const Center(child: CircularProgressIndicator()),
      );
    }
    final info = _info!;
    return Scaffold(
      appBar: MyAppbar(title: '学习详情'),
      body: SafeArea(
        child: Column(
          children: [
            _buildVideoOrCover(screenWidth(context), 250),
            const SizedBox(height: 5),
            Container(
              width: double.infinity,
              color: Colors.white,
              padding: const EdgeInsets.all(10.0),
              child: Text(
                info['CURRICULUMNAME'] ?? '',
                style: const TextStyle(
                  fontSize: 20,
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
            const SizedBox(height: 10),
            Container(
              color: Colors.white,
              child: TabBar(
                controller: _tabController,
                labelStyle: const TextStyle(fontSize: 16),
                indicator: const UnderlineTabIndicator(
                  borderSide: BorderSide(width: 3.0, color: Colors.blue),
                  insets: EdgeInsets.symmetric(horizontal: 0.0),
                ),
                labelColor: Colors.blue,
                unselectedLabelColor: Colors.grey,
                tabs: const [Tab(text: '课件目录'), Tab(text: '详情')],
              ),
            ),
            const SizedBox(height: 10),
            Expanded(
              child: TabBarView(
                controller: _tabController,
                children: [_buildVideoList(), _buildDetailView(info)],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildVideoList() {
    return ListView.builder(
      itemCount: _videoList.length,
      itemBuilder: (ctx, idx) {
        final item = _videoList[idx] as Map<String, dynamic>;
        final nodes = item['nodes'] as List<dynamic>?;
        if (nodes != null && nodes.isNotEmpty) {
          // 章节标题 + 直接展开的子项列表（不折叠）
          return Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              ...nodes.asMap().entries.map(
                (e) => _buildVideoItem(
                  item,
                  e.value as Map<String, dynamic>,
                  true,
                  idx,
                  e.key,
                ),
              ),
              const Divider(height: 1), // 每章节后一个分割线
            ],
          );
        }
        // 没有子节点，直接显示该条目
        return _buildVideoItem(item, item, false, idx, 0);
      },
    );
  }

  Widget _buildVideoItem(
    Map<String, dynamic> item,
    Map<String, dynamic> m,
    bool hasNodes,
    int fi,
    int ni,
  ) {
    return Container(
      color: Colors.white,
      padding: const EdgeInsets.all(20),
      child: Column(
        children: [
          Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Icon(Icons.file_copy_rounded, color: Colors.grey, size: 20),
              const SizedBox(width: 8),
              Expanded(
                child: Text(
                  item['NAME'] ?? '',
                  style: const TextStyle(fontSize: 14),
                ),
              ),
            ],
          ),
          const SizedBox(height: 10),
          GestureDetector(
            onTap: () => _onVideoTap(m, hasNodes, fi, ni),
            child: Container(
              height: 80,
              padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 8),
              decoration: BoxDecoration(
                color: const Color(0xFFFAFAFA),
                borderRadius: BorderRadius.circular(5),
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Expanded(
                    child: Text(
                      m['COURSEWARENAME'] ?? '',
                      style: const TextStyle(fontSize: 14),
                    ),
                  ),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Expanded(
                        child: Text(
                          "进度：${m['percent']}",
                          style: const TextStyle(color: Colors.blue),
                        ),
                      ),
                      if (m['IS_VIDEO'] == 0) ...[
                        Text(secondsCount(m['VIDEOTIME'])),
                        const SizedBox(width: 20),
                        const Icon(Icons.play_circle, color: Colors.blue),
                      ],
                      SizedBox(width: 20),
                      CustomButton(
                        onPressed:
                            () => pushPage(
                              StudyPractisePage(
                                videoCoursewareId: m['VIDEOCOURSEWARE_ID'],
                              ),
                              context,
                            ),
                        text: "课后练习",
                        backgroundColor: Colors.blue,
                        height: 30,
                        textStyle: const TextStyle(
                          fontSize: 12,
                          color: Colors.white,
                        ),
                        padding: const EdgeInsets.symmetric(
                          vertical: 2,
                          horizontal: 12,
                        ),
                        borderRadius: 15,
                      ),
                    ],
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildDetailView(Map info) {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            info['CURRICULUMINTRODUCE'] ?? '',
            style: const TextStyle(fontSize: 16),
          ),
          const SizedBox(height: 16),
          if (info['COVERPATH'] != null)
            Image.network(ApiService.baseImgPath + info['COVERPATH']),
        ],
      ),
    );
  }
}
