import 'dart:async';
import 'dart:io';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:recording_tool/core/permission/permission_service.dart';
import 'package:recording_tool/features/recording/model/model_recording.dart';
import 'package:recording_tool/features/recording/model/model_recording_context.dart';
import 'package:recording_tool/features/recording/model/model_recording_session.dart';
import 'package:recording_tool/features/recording/platform/recording_platform.dart';

/// 录制页状态 Provider。
final recordingViewModelProvider =
    NotifierProvider<RecordingViewModel, RecordingModel>(
      RecordingViewModel.new,
    );

/// 开始录制所需的相机/麦克风权限检测结果。
class RecordingRequiredPermissions {
  const RecordingRequiredPermissions({
    required this.cameraGranted,
    required this.microphoneGranted,
  });

  final bool cameraGranted;
  final bool microphoneGranted;

  bool get allGranted => cameraGranted && microphoneGranted;
}

/// 录制页 ViewModel：赛事上下文、权限、推流与页面状态。
class RecordingViewModel extends Notifier<RecordingModel> {
  Timer? _elapsedTimer;
  DateTime? _recordingStartedAt;

  /// 初始化状态并注册销毁回调。
  @override
  RecordingModel build() {
    ref.onDispose(_dispose);
    return RecordingModel(recordingContext: const RecordingContext.empty());
  }

  /// 局部更新 session 子状态。
  void _updateSession(
    RecordingSessionState Function(RecordingSessionState session) update,
  ) {
    state = state.copyWith(session: update(state.session));
  }

  /// 设置当前录制页上下文。
  void setRecordingContext(RecordingContext recordingContext) {
    state = state.copyWith(recordingContext: recordingContext);
  }

  /// 申请权限并检查系统设置。
  Future<void> prepareSession() async {
    if (!RecordingPlatform.isSupported) {
      _updateSession((s) => s.copyWith(errorMessage: '当前设备不支持录制'));
      return;
    }

    final permissions = await PermissionService.requestMissing([
      Permission.camera,
      Permission.microphone,
      if (Platform.isAndroid) Permission.notification,
    ]);

    final cameraGranted = permissions[Permission.camera]?.isGranted ?? false;
    if (!cameraGranted) {
      _updateSession((s) => s.copyWith(errorMessage: '需要相机权限才能录制'));
      return;
    }

    final microphoneGranted =
        permissions[Permission.microphone]?.isGranted ?? false;
    final notificationsGranted = Platform.isAndroid
        ? (permissions[Permission.notification]?.isGranted ?? false)
        : true;

    final warnings = <String>[];
    if (Platform.isAndroid && !notificationsGranted) {
      warnings.add('未授予通知权限，录制时可能看不到前台服务通知，系统更容易结束后台录制');
    }
    if (!microphoneGranted) {
      warnings.add('未授予麦克风权限，当前将以静音模式录制');
    }
    final hasDnd = await RecordingPlatform.hasNotificationPolicyAccess();
    final batteryIgnored =
        await RecordingPlatform.isIgnoringBatteryOptimizations();

    _updateSession(
      (s) => s.copyWith(
        hasDndAccess: hasDnd,
        isBatteryOptimizedIgnored: batteryIgnored,
        isMicrophoneGranted: microphoneGranted,
        notificationsGranted: notificationsGranted,
        permissionWarning: warnings.isEmpty ? null : warnings.join('\n'),
        errorMessage: null,
        clearPermissionWarning: warnings.isEmpty,
      ),
    );

    _updateSession((s) => s.copyWith(errorMessage: null));
  }

  void setPreviewReady({required bool ready, String? errorMessage}) {
    _updateSession(
      (s) => s.copyWith(isPreviewReady: ready, errorMessage: errorMessage),
    );
  }

  /// 检测并尝试申请相机、麦克风权限，同步更新 session 中的 isMicrophoneGranted。
  Future<RecordingRequiredPermissions>
  ensureCameraAndMicrophonePermissions() async {
    final permissions = await PermissionService.requestMissing([
      Permission.camera,
      Permission.microphone,
    ]);

    final cameraGranted = _isPermissionGranted(permissions[Permission.camera]);
    final microphoneGranted = _isPermissionGranted(
      permissions[Permission.microphone],
    );

    _updateSession((s) => s.copyWith(isMicrophoneGranted: microphoneGranted));

    if (cameraGranted && !state.session.isPreviewReady) {
      _updateSession((s) => s.copyWith(errorMessage: null));
      _updateSession((s) => s.copyWith(isPreviewReady: true));
    }

    return RecordingRequiredPermissions(
      cameraGranted: cameraGranted,
      microphoneGranted: microphoneGranted,
    );
  }

  bool _isPermissionGranted(PermissionStatus? status) {
    return status?.isGranted == true || status?.isLimited == true;
  }

  void updateZoomCapabilities({
    required double zoomRatio,
    required double minZoomRatio,
    required double maxZoomRatio,
  }) {
    _updateSession(
      (s) => s.copyWith(
        zoomRatio: zoomRatio,
        minZoomRatio: minZoomRatio,
        maxZoomRatio: maxZoomRatio,
        errorMessage: null,
      ),
    );
  }

  void markLensSwitching(bool switching) {
    _updateSession((s) => s.copyWith(isSwitchingLens: switching));
  }

  void setZoomRatioValue(double ratio) {
    _updateSession((s) => s.copyWith(zoomRatio: ratio, errorMessage: null));
  }

  void setError(String message) {
    _updateSession((s) => s.copyWith(errorMessage: message));
  }

  void markStartingRecording() {
    _updateSession(
      (s) => s.copyWith(
        isStartingRecording: true,
        errorMessage: null,
        clearStreamResult: true,
      ),
    );
  }

  Future<void> markRecordingStarted(String streamUrl) async {
    if (state.session.hasDndAccess) {
      await RecordingPlatform.enableDoNotDisturb();
    }
    _recordingStartedAt = DateTime.now();
    _elapsedTimer?.cancel();
    _elapsedTimer = Timer.periodic(const Duration(seconds: 1), (_) {
      final startedAt = _recordingStartedAt;
      if (startedAt == null) return;
      final elapsed = DateTime.now().difference(startedAt).inMilliseconds;
      _updateSession(
        (s) => s.copyWith(
          status: RecordingStatus(
            state: RecordingState.recording,
            streamUrl: streamUrl,
            elapsedMillis: elapsed,
          ),
        ),
      );
    });
    _updateSession(
      (s) => s.copyWith(
        status: RecordingStatus(
          state: RecordingState.recording,
          streamUrl: streamUrl,
        ),
        lastStreamUrl: streamUrl,
        isStartingRecording: false,
        isTouchLocked: true,
        errorMessage: null,
        streamFailed: false,
        clearStreamResult: true,
      ),
    );
  }

  void markRecordingStartFailed(String message) {
    _recordingStartedAt = null;
    _elapsedTimer?.cancel();
    _elapsedTimer = null;
    _updateSession(
      (s) => s.copyWith(
        status: const RecordingStatus(state: RecordingState.previewing),
        isStartingRecording: false,
        errorMessage: message,
        streamFailed: true,
      ),
    );
  }

  Future<void> markRecordingStopped({String? errorMessage}) async {
    final lastStreamUrl = state.session.lastStreamUrl;
    final elapsed = _recordingStartedAt == null
        ? state.session.status.elapsedMillis
        : DateTime.now().difference(_recordingStartedAt!).inMilliseconds;
    _recordingStartedAt = null;
    _elapsedTimer?.cancel();
    _elapsedTimer = null;
    await RecordingPlatform.disableDoNotDisturb();
    _updateSession(
      (s) => s.copyWith(
        status: RecordingStatus(
          state: RecordingState.previewing,
          streamUrl: lastStreamUrl,
          elapsedMillis: elapsed,
        ),
        isStartingRecording: false,
        errorMessage: errorMessage,
        streamFinished: errorMessage == null,
        streamFailed: errorMessage != null,
      ),
    );
  }

  /// 切换录制中触屏锁定状态。
  void setTouchLocked(bool locked) {
    _updateSession((s) => s.copyWith(isTouchLocked: locked));
  }

  /// 清除上次推流完成结果标记。
  void clearSavedRecordingResult() {
    _updateSession((s) => s.copyWith(clearStreamResult: true));
  }

  /// 跳转系统勿扰/通知策略设置页。
  Future<void> openDndSettings() =>
      RecordingPlatform.openNotificationPolicySettings();

  /// 重新检测勿扰模式权限并更新状态。
  Future<void> refreshDndAccess() async {
    final hasDnd = await RecordingPlatform.hasNotificationPolicyAccess();
    _updateSession((s) => s.copyWith(hasDndAccess: hasDnd));
  }

  /// 跳转电池优化白名单设置页。
  Future<void> openBatterySettings() =>
      RecordingPlatform.openBatteryOptimizationSettings();

  /// 重新检测是否已忽略电池优化并更新状态。
  Future<void> refreshBatteryOptimization() async {
    final ignored = await RecordingPlatform.isIgnoringBatteryOptimizations();
    _updateSession((s) => s.copyWith(isBatteryOptimizedIgnored: ignored));
  }

  /// 退出录制页时释放相机、勿扰和状态订阅。
  Future<void> teardown() async {
    await RecordingPlatform.setImmersiveMode(enabled: false);
    await RecordingPlatform.disableDoNotDisturb();
    _recordingStartedAt = null;
    _elapsedTimer?.cancel();
    _elapsedTimer = null;
    state = state.copyWith(session: const RecordingSessionState());
  }

  /// Provider 销毁时取消状态流订阅。
  Future<void> _dispose() async {
    _elapsedTimer?.cancel();
  }
}
