import 'dart:io';

import 'package:apivideo_live_stream/apivideo_live_stream.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:recording_tool/app/router/app_navigator.dart';
import 'package:recording_tool/core/platform/app_platform_info.dart';
import 'package:recording_tool/core/platform/device_health_checker.dart';
import 'package:recording_tool/features/recording/dialog/dialog-record.dart';
import 'package:recording_tool/features/recording/model/model_recording_context.dart';
import 'package:recording_tool/features/recording/platform/recording_platform.dart';
import 'package:recording_tool/features/recording/view-model/view_model_recording.dart';
import 'package:recording_tool/features/recording/widgets/widget_camera_preview.dart';
import 'package:recording_tool/features/recording/widgets/widget_record_footer.dart';
import 'package:recording_tool/features/recording/widgets/widget_record_header.dart';
import 'package:recording_tool/features/recording/widgets/widget_record_timer.dart';
import 'package:recording_tool/features/recording/widgets/widget_recording_hud.dart';
import 'package:recording_tool/features/recording/widgets/widget_recording_loading_overlay.dart';
import 'package:recording_tool/features/recording/widgets/widget_recording_saved_dialog.dart';
import 'package:recording_tool/features/recording/widgets/widget_recording_touch_lock_overlay.dart';
import 'package:recording_tool/features/scan_qrcode/pages/page_scan_qrcode.dart';
import 'package:recording_tool/features/scan_qrcode/utils/rtmp_stream_target.dart';
import 'package:recording_tool/shared/widgets/widgets.dart';

/// 录制页入口
class RecordingPage extends ConsumerStatefulWidget {
  const RecordingPage({
    super.key,
    required this.recordingContext,
    required this.streamUrl,
  });

  final RecordingContext recordingContext;
  final String streamUrl;

  @override
  /// 创建页面状态
  ConsumerState<RecordingPage> createState() => _RecordingPageState();
}

class _RecordingPageState extends ConsumerState<RecordingPage> {
  late final ApiVideoLiveStreamController _streamController;
  var _immersiveApplied = false;
  var _previewReady = false;
  var _stoppingByUser = false;
  var _controllerDisposed = false;
  String? _mainCameraId;
  String? _ultraWideCameraId;
  double _ultraWideZoomRatio = 1.0;

  @override
  /// 首帧后初始化录制流程
  void initState() {
    super.initState();
    _streamController = ApiVideoLiveStreamController(
      initialAudioConfig: AudioConfig(bitrate: 128000),
      initialVideoConfig: VideoConfig.withDefaultBitrate(
        resolution: Resolution.RESOLUTION_1080,
        fps: 30,
      ),
      onConnectionSuccess: () => {debugPrint('推流成功')},
      onConnectionFailed: (reason) {
        debugPrint('推流失败');

        if (!mounted) return;
        ref
            .read(recordingViewModelProvider.notifier)
            .markRecordingStartFailed('推流失败: $reason');
      },
      onDisconnection: () {
        debugPrint('推流连接已断开');

        if (!mounted || _stoppingByUser) return;
        final isRecording = ref.read(recordingViewModelProvider).isRecording;
        if (isRecording) {
          ref
              .read(recordingViewModelProvider.notifier)
              .markRecordingStopped(errorMessage: '推流连接已断开');
        }
      },
      onError: (error) {
        debugPrint('推流失败：${error.toString()}');
        if (!mounted) return;
        ref
            .read(recordingViewModelProvider.notifier)
            .setError(error.toString());
      },
    );

    WidgetsBinding.instance.addPostFrameCallback((_) {
      ref
          .read(recordingViewModelProvider.notifier)
          .setRecordingContext(widget.recordingContext);
      _bootstrap();
    });
  }

  /// 检查设备健康状态并弹窗提示
  Future<void> _checkAndShowDeviceHealthAlerts() async {
    final snapshot = await AppPlatformInfo.deviceHealth();
    if (!mounted) return;

    final lines = DeviceHealthChecker.warningLines(snapshot);
    if (lines.isEmpty) return;

    await RecordDialog.showSingle(
      context,
      title: lines.join('\n'),
      buttonText: '确定',
    );
  }

  /// 页面启动：健康检查、进入录制模式、准备相机会话
  Future<void> _bootstrap() async {
    await _checkAndShowDeviceHealthAlerts();
    if (!mounted) return;

    await _enterRecordingMode();
    if (!mounted) return;
    await ref.read(recordingViewModelProvider.notifier).prepareSession();
    if (!mounted) return;
    await _initializeLiveStreamPreview();
  }

  Future<void> _initializeLiveStreamPreview() async {
    try {
      await _streamController.initialize();
      if (!mounted) return;
      setState(() => _previewReady = true);
      ref
          .read(recordingViewModelProvider.notifier)
          .setPreviewReady(ready: true);
      await _loadBackCameraCapabilities();
    } on PlatformException catch (error) {
      if (!mounted) return;
      ref
          .read(recordingViewModelProvider.notifier)
          .setPreviewReady(
            ready: false,
            errorMessage: error.message ?? '相机预览初始化失败',
          );
      if (mounted) setState(() => _previewReady = false);
    } catch (error) {
      if (!mounted) return;
      ref
          .read(recordingViewModelProvider.notifier)
          .setPreviewReady(ready: false, errorMessage: '相机预览初始化失败: $error');
      setState(() => _previewReady = false);
    }
  }

  Future<void> _loadBackCameraCapabilities() async {
    try {
      final cameras = await _streamController.getBackCameras();
      if (cameras.isEmpty) return;
      final main = cameras.first;
      final widest = cameras.reduce(
        (current, next) =>
            next.horizontalFov > current.horizontalFov ? next : current,
      );
      _mainCameraId = main.cameraId;
      if (widest.cameraId != main.cameraId &&
          widest.horizontalFov > main.horizontalFov * 1.08 &&
          main.minFocalLength > 0) {
        _ultraWideCameraId = widest.cameraId;
        _ultraWideZoomRatio = (widest.minFocalLength / main.minFocalLength)
            .clamp(0.4, 0.9)
            .toDouble();
      }
      ref
          .read(recordingViewModelProvider.notifier)
          .updateZoomCapabilities(
            zoomRatio: 1.0,
            minZoomRatio: _ultraWideCameraId == null
                ? 1.0
                : _ultraWideZoomRatio,
            maxZoomRatio: 1.0,
          );
    } catch (_) {
      ref
          .read(recordingViewModelProvider.notifier)
          .updateZoomCapabilities(
            zoomRatio: 1.0,
            minZoomRatio: 1.0,
            maxZoomRatio: 1.0,
          );
    }
  }

  /// Android 进入沉浸式全屏
  Future<void> _enterRecordingMode() async {
    if (!Platform.isAndroid) return;
    await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
    await RecordingPlatform.setImmersiveMode(enabled: true);
    _immersiveApplied = true;
  }

  /// 根据缺失权限生成弹窗文案。
  String _recordingPermissionDialogTitle(RecordingRequiredPermissions result) {
    if (!result.cameraGranted && !result.microphoneGranted) {
      return '录制需要开启相机和录音权限，请在系统设置中授权后重试';
    }
    if (!result.cameraGranted) {
      return '录制需要开启相机权限，请在系统设置中授权后重试';
    }
    return '录制需要开启录音权限，请在系统设置中授权后重试';
  }

  /// 开始录制前检测相机、录音权限，未授予则弹窗并跳转系统设置。
  Future<bool> _ensureRecordingPermissions() async {
    final result = await ref
        .read(recordingViewModelProvider.notifier)
        .ensureCameraAndMicrophonePermissions();
    if (result.allGranted) {
      final ready = ref.read(recordingViewModelProvider).session.isPreviewReady;
      if (ready) return true;
      if (!mounted) return false;
      AppToast.show('相机预览启动失败，请重试');
      return false;
    }
    if (!mounted) return false;

    await RecordDialog.showSingle(
      context,
      title: _recordingPermissionDialogTitle(result),
      buttonText: '确定',
      onPressed: openAppSettings,
    );
    return false;
  }

  /// 点击开始录制：校验推流地址、权限与健康状态
  Future<void> _onStartRecording() async {
    if (widget.streamUrl.trim().isEmpty) {
      AppToast.show('推流地址为空，请重新进入录制页');
      return;
    }
    if (!await _ensureRecordingPermissions()) return;
    if (!mounted) return;
    await _checkAndShowDeviceHealthAlerts();
    if (!mounted) return;
    final viewModel = ref.read(recordingViewModelProvider.notifier);
    viewModel.markStartingRecording();
    try {
      final target = RtmpStreamTarget.parse(widget.streamUrl);
      await _streamController.startStreaming(
        streamKey: target.streamKey,
        url: target.url,
      );
      if (!mounted) return;
      await viewModel.markRecordingStarted(target.fullUrl);
    } on FormatException catch (error) {
      viewModel.markRecordingStartFailed(error.message);
      AppToast.show(error.message);
    } on PlatformException catch (error) {
      final message = error.message ?? error.code;
      viewModel.markRecordingStartFailed('推流失败: $message');
      AppToast.show('推流失败: $message');
    } catch (error) {
      viewModel.markRecordingStartFailed('推流失败: $error');
      AppToast.showError(error);
    }
  }

  /// 停止录制并按结果显示推流提示。
  Future<void> _stopRecordingAndShowResult() async {
    final viewModel = ref.read(recordingViewModelProvider.notifier);
    _stoppingByUser = true;
    try {
      await _streamController.stopStreaming();
      if (!mounted) return;
      await viewModel.markRecordingStopped();
    } on PlatformException catch (error) {
      final message = error.message ?? error.code;
      await viewModel.markRecordingStopped(errorMessage: '停止推流失败: $message');
      AppToast.show('停止推流失败: $message');
      return;
    } catch (error) {
      await viewModel.markRecordingStopped(errorMessage: '停止推流失败: $error');
      AppToast.showError(error);
      return;
    } finally {
      _stoppingByUser = false;
    }
    await _showRecordingFinishedDialogIfNeeded();
  }

  Future<void> _setCameraZoomRatio(double ratio) async {
    final viewModel = ref.read(recordingViewModelProvider.notifier);
    final targetCameraId = ratio < 1.0 ? _ultraWideCameraId : _mainCameraId;
    if (targetCameraId == null) {
      viewModel.setError('当前设备不支持该镜头');
      return;
    }
    viewModel.markLensSwitching(true);
    try {
      await _streamController.setCameraId(targetCameraId);
      viewModel.setZoomRatioValue(ratio < 1.0 ? _ultraWideZoomRatio : 1.0);
    } on PlatformException catch (error) {
      final isRecording = ref.read(recordingViewModelProvider).isRecording;
      final message = isRecording
          ? '推流中切换镜头失败，请停止后重试'
          : (error.message ?? '切换镜头失败，请重试');
      viewModel.setError(message);
    } catch (_) {
      final isRecording = ref.read(recordingViewModelProvider).isRecording;
      viewModel.setError(isRecording ? '推流中切换镜头失败，请停止后重试' : '切换镜头失败，请重试');
    } finally {
      viewModel.markLensSwitching(false);
    }
  }

  /// 返回扫码页，准备新一轮录制。
  void _recordNewRound() {
    AppNavigator.pushAndRemoveUntil(const ScanQrCodePage());
  }

  /// 推流结束后按需弹出完成对话框
  Future<void> _showRecordingFinishedDialogIfNeeded() async {
    final recordingInfo = ref.read(recordingViewModelProvider);
    final session = recordingInfo.session;
    if (!session.streamFinished || session.streamFailed) {
      return;
    }

    await showRecordingSavedDialog(
      context,
      sessionTitle: recordingInfo.recordingContext.title,
      onContinueRound: () {
        ref
            .read(recordingViewModelProvider.notifier)
            .clearSavedRecordingResult();
      },
      onRecordNewRound: _recordNewRound,
    );
  }

  /// 退出沉浸式并释放录制会话
  Future<void> _exitRecordingMode() async {
    if (!_immersiveApplied) return;
    await ref.read(recordingViewModelProvider.notifier).teardown();
    await _disposeStreamController();
    await SystemChrome.setEnabledSystemUIMode(
      SystemUiMode.manual,
      overlays: SystemUiOverlay.values,
    );
    await RecordingPlatform.setImmersiveMode(enabled: false);
    _immersiveApplied = false;
  }

  @override
  /// 页面销毁时恢复系统 UI
  void dispose() {
    if (_immersiveApplied) {
      SystemChrome.setEnabledSystemUIMode(
        SystemUiMode.manual,
        overlays: SystemUiOverlay.values,
      );
      RecordingPlatform.setImmersiveMode(enabled: false);
    }
    _disposeStreamController();
    super.dispose();
  }

  Future<void> _disposeStreamController() async {
    if (_controllerDisposed) return;
    _controllerDisposed = true;
    await _streamController.stop();
    await _streamController.dispose();
  }

  @override
  /// 构建录制页 UI
  Widget build(BuildContext context) {
    return _RecordingPopScope(
      onExitRecordingMode: _exitRecordingMode,
      child: Scaffold(
        backgroundColor: Colors.black,
        body: Column(
          children: [
            const _RecordHeaderSection(),
            Expanded(
              child: Stack(
                children: [
                  CameraPreviewWidget(
                    controller: _streamController,
                    isReady: _previewReady,
                  ),
                  const _PreviewLoadingLayer(),
                  const RecordTimerWidget(),
                  _RecordingHudLayer(
                    onStart: _onStartRecording,
                    onStop: _stopRecordingAndShowResult,
                    onZoomSelected: _setCameraZoomRatio,
                  ),
                  _TouchLockOverlayLayer(
                    onStopRecording: _stopRecordingAndShowResult,
                  ),
                  const _StartingRecordingOverlay(),
                ],
              ),
            ),
            const RecordFooter(),
          ],
        ),
      ),
    );
  }
}

class _RecordingPopScope extends ConsumerWidget {
  const _RecordingPopScope({
    required this.onExitRecordingMode,
    required this.child,
  });

  final Future<void> Function() onExitRecordingMode;
  final Widget child;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final isRecording = ref.watch(
      recordingViewModelProvider.select((m) => m.session.isRecording),
    );

    return PopScope(
      canPop: !isRecording,
      onPopInvokedWithResult: (didPop, result) async {
        if (didPop) {
          await onExitRecordingMode();
          return;
        }
        if (isRecording) {
          AppToast.show('录制中无法返回，请先停止录制');
        }
      },
      child: child,
    );
  }
}

class _RecordHeaderSection extends ConsumerWidget {
  const _RecordHeaderSection();

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final headerState = ref.watch(
      recordingViewModelProvider.select(
        (m) => (m.recordingContext.title, m.session.isRecording),
      ),
    );
    final (eventTitle, isRecording) = headerState;

    return RecordHeaderWidget(eventTitle: eventTitle, isRecording: isRecording);
  }
}

class _PreviewLoadingLayer extends ConsumerWidget {
  const _PreviewLoadingLayer();

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final showLoading = ref.watch(
      recordingViewModelProvider.select(
        (m) => !m.session.isPreviewReady && m.session.errorMessage == null,
      ),
    );

    if (!showLoading) {
      return const SizedBox.shrink();
    }

    return const RecordingLoadingOverlayWidget(message: '正在启动相机…');
  }
}

class _RecordingHudLayer extends ConsumerWidget {
  const _RecordingHudLayer({
    required this.onStart,
    required this.onStop,
    required this.onZoomSelected,
  });

  final Future<void> Function() onStart;
  final Future<void> Function() onStop;
  final ValueChanged<double> onZoomSelected;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final hudState = ref.watch(
      recordingViewModelProvider.select(
        (m) => (
          m.session.errorMessage,
          m.session.permissionWarning,
          m.session.hasDndAccess,
          m.session.isBatteryOptimizedIgnored,
          m.session.notificationsGranted,
          m.session.isRecording,
          m.session.isStartingRecording,
          m.session.isSwitchingLens,
          m.session.isTouchLocked,
          m.session.zoomRatio,
          m.session.minZoomRatio,
          m.session.maxZoomRatio,
          m.recordingContext.address.trim(),
        ),
      ),
    );
    final (
      errorMessage,
      permissionWarning,
      hasDndAccess,
      isBatteryOptimizedIgnored,
      notificationsGranted,
      isRecording,
      isStartingRecording,
      isSwitchingLens,
      isTouchLocked,
      zoomRatio,
      minZoomRatio,
      maxZoomRatio,
      venue,
    ) = hudState;
    final viewModel = ref.read(recordingViewModelProvider.notifier);

    return RecordingHudWidget(
      errorMessage: errorMessage,
      permissionWarning: permissionWarning,
      hasDndAccess: hasDndAccess,
      isBatteryOptimizedIgnored: isBatteryOptimizedIgnored,
      notificationsGranted: notificationsGranted,
      isRecording: isRecording,
      isStartingRecording: isStartingRecording,
      isSwitchingLens: isSwitchingLens,
      isTouchLocked: isTouchLocked,
      zoomRatio: zoomRatio,
      minZoomRatio: minZoomRatio,
      maxZoomRatio: maxZoomRatio,
      showContextHint: venue.isNotEmpty,
      contextAddress: venue,
      onStart: onStart,
      onStop: onStop,
      onOpenDnd: () async {
        await viewModel.openDndSettings();
        await viewModel.refreshDndAccess();
      },
      onOpenBattery: () async {
        await viewModel.openBatterySettings();
        await viewModel.refreshBatteryOptimization();
      },
      onToggleTouchLock: () {
        final locked = ref
            .read(recordingViewModelProvider)
            .session
            .isTouchLocked;
        viewModel.setTouchLocked(!locked);
      },
      onZoomSelected: onZoomSelected,
    );
  }
}

class _TouchLockOverlayLayer extends ConsumerWidget {
  const _TouchLockOverlayLayer({required this.onStopRecording});

  final Future<void> Function() onStopRecording;

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final overlayState = ref.watch(
      recordingViewModelProvider.select(
        (m) => (m.session.isTouchLocked, m.session.isRecording),
      ),
    );
    final (isTouchLocked, isRecording) = overlayState;

    if (!isTouchLocked || !isRecording) {
      return const SizedBox.shrink();
    }

    final viewModel = ref.read(recordingViewModelProvider.notifier);

    return RecordingTouchLockOverlayWidget(
      enabled: true,
      onUnlocked: (intent) async {
        viewModel.setTouchLocked(false);
        if (intent == RecordingTouchLockUnlockIntent.stopRecording) {
          await onStopRecording();
        }
      },
    );
  }
}

class _StartingRecordingOverlay extends ConsumerWidget {
  const _StartingRecordingOverlay();

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final isStartingRecording = ref.watch(
      recordingViewModelProvider.select((m) => m.session.isStartingRecording),
    );

    if (!isStartingRecording) {
      return const SizedBox.shrink();
    }

    return RecordingLoadingOverlayWidget(
      message: '正在连接推流…',
      backgroundColor: Colors.black.withValues(alpha: 0.24),
    );
  }
}
