import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../core/contracts/player_gestures.dart';
import 'shared/settings_persistence.dart';

class PlayerSettingsState {
  final String hwdecMode;
  final double volume;
  final int seekForwardSeconds;
  final int seekBackwardSeconds;

  final double keyboardHoldLeftSpeed;
  final double keyboardHoldRightSpeed;

  final GestureAction mouseLeftClickAction;
  final GestureAction mouseLeftDoubleClickAction;
  final GestureAction mouseRightClickAction;
  final GestureAction mouseRightDoubleClickAction;
  final bool autoPip;
  final bool pipShowEpisodeActions;
  final double? androidBrightness;

  const PlayerSettingsState({
    this.hwdecMode = 'auto-copy',
    this.volume = 100.0,
    this.seekForwardSeconds = 15,
    this.seekBackwardSeconds = 15,
    this.keyboardHoldLeftSpeed = 0.5,
    this.keyboardHoldRightSpeed = 3.0,
    this.mouseLeftClickAction = GestureAction.playPause,
    this.mouseLeftDoubleClickAction = GestureAction.fullscreen,
    this.mouseRightClickAction = GestureAction.toggleControls,
    this.mouseRightDoubleClickAction = GestureAction.none,
    this.autoPip = true,
    this.pipShowEpisodeActions = true,
    this.androidBrightness,
  });

  PlayerSettingsState copyWith({
    String? hwdecMode,
    double? volume,
    int? seekForwardSeconds,
    int? seekBackwardSeconds,
    double? keyboardHoldLeftSpeed,
    double? keyboardHoldRightSpeed,
    GestureAction? mouseLeftClickAction,
    GestureAction? mouseLeftDoubleClickAction,
    GestureAction? mouseRightClickAction,
    GestureAction? mouseRightDoubleClickAction,
    bool? autoPip,
    bool? pipShowEpisodeActions,
    double? androidBrightness,
  }) => PlayerSettingsState(
    hwdecMode: hwdecMode ?? this.hwdecMode,
    volume: volume ?? this.volume,
    seekForwardSeconds: seekForwardSeconds ?? this.seekForwardSeconds,
    seekBackwardSeconds: seekBackwardSeconds ?? this.seekBackwardSeconds,
    keyboardHoldLeftSpeed: keyboardHoldLeftSpeed ?? this.keyboardHoldLeftSpeed,
    keyboardHoldRightSpeed:
        keyboardHoldRightSpeed ?? this.keyboardHoldRightSpeed,
    mouseLeftClickAction: mouseLeftClickAction ?? this.mouseLeftClickAction,
    mouseLeftDoubleClickAction:
        mouseLeftDoubleClickAction ?? this.mouseLeftDoubleClickAction,
    mouseRightClickAction: mouseRightClickAction ?? this.mouseRightClickAction,
    mouseRightDoubleClickAction:
        mouseRightDoubleClickAction ?? this.mouseRightDoubleClickAction,
    autoPip: autoPip ?? this.autoPip,
    pipShowEpisodeActions: pipShowEpisodeActions ?? this.pipShowEpisodeActions,
    androidBrightness: androidBrightness ?? this.androidBrightness,
  );
}

class PlayerSettingsNotifier extends AsyncNotifier<PlayerSettingsState>
    with SettingsPersistence {
  static const _keyHwdec = 'smplayer.player_hwdec';
  static const _legacyKeyEnginePreference = 'smplayer.player_engine_preference';
  static const _keyVolume = 'smplayer.player_volume';
  static const _keySeekForward = 'smplayer.player_seek_forward';
  static const _keySeekBackward = 'smplayer.player_seek_backward';
  static const _keyKbdHoldLeft = 'smplayer.gesture_kbd_hold_left_speed';
  static const _keyKbdHoldRight = 'smplayer.gesture_kbd_hold_right_speed';
  static const _keyMouseLeftClick = 'smplayer.gesture_mouse_left_click';
  static const _keyMouseLeftDblClick = 'smplayer.gesture_mouse_left_dbl_click';
  static const _keyMouseRightClick = 'smplayer.gesture_mouse_right_click';
  static const _keyMouseRightDblClick =
      'smplayer.gesture_mouse_right_dbl_click';
  static const _keyAutoPip = 'smplayer.player_auto_pip';
  static const _keyPipEpisodeActions = 'smplayer.player_pip_episode_actions';
  static const _keyAndroidBrightness = 'smplayer.player_android_brightness';

  static const _speedAllowed = <double>[
    0.5,
    0.75,
    1.0,
    1.25,
    1.5,
    1.75,
    2.0,
    2.5,
    3.0,
    4.0,
    8.0,
  ];

  static double _normalizeSpeed(double v, double fallback) {
    for (final s in _speedAllowed) {
      if ((s - v).abs() < 0.001) return s;
    }
    return fallback;
  }

  @override
  Future<PlayerSettingsState> build() async {
    final prefs = await getPrefs();
    if (prefs.containsKey(_keyHwdec)) {
      await prefs.remove(_keyHwdec);
    }
    const hwdec = 'auto-copy';
    final volume = prefs.getDouble(_keyVolume) ?? 100.0;
    final seekFwd = prefs.getInt(_keySeekForward) ?? 15;
    final seekBwd = prefs.getInt(_keySeekBackward) ?? 15;
    if (prefs.containsKey(_legacyKeyEnginePreference)) {
      await prefs.remove(_legacyKeyEnginePreference);
    }
    final holdLeft = _normalizeSpeed(
      prefs.getDouble(_keyKbdHoldLeft) ?? 0.5,
      0.5,
    );
    final holdRight = _normalizeSpeed(
      prefs.getDouble(_keyKbdHoldRight) ?? 3.0,
      3.0,
    );
    final autoPip = prefs.getBool(_keyAutoPip) ?? true;
    final pipEpisodeActions = prefs.getBool(_keyPipEpisodeActions) ?? true;
    final androidBrightness = prefs
        .getDouble(_keyAndroidBrightness)
        ?.clamp(0.0, 1.0);
    return PlayerSettingsState(
      hwdecMode: hwdec,
      volume: volume.clamp(0.0, 200.0),
      seekForwardSeconds: seekFwd.clamp(5, 120),
      seekBackwardSeconds: seekBwd.clamp(5, 120),
      keyboardHoldLeftSpeed: holdLeft,
      keyboardHoldRightSpeed: holdRight,
      mouseLeftClickAction: gestureActionFromName(
        prefs.getString(_keyMouseLeftClick),
        GestureAction.playPause,
      ),
      mouseLeftDoubleClickAction: gestureActionFromName(
        prefs.getString(_keyMouseLeftDblClick),
        GestureAction.fullscreen,
      ),
      mouseRightClickAction: gestureActionFromName(
        prefs.getString(_keyMouseRightClick),
        GestureAction.toggleControls,
      ),
      mouseRightDoubleClickAction: gestureActionFromName(
        prefs.getString(_keyMouseRightDblClick),
        GestureAction.none,
      ),
      autoPip: autoPip,
      pipShowEpisodeActions: pipEpisodeActions,
      androidBrightness: androidBrightness,
    );
  }

  Future<void> setVolume(double volume) async {
    final clamped = volume.clamp(0.0, 200.0);
    final current = state.value ?? const PlayerSettingsState();
    state = AsyncValue.data(current.copyWith(volume: clamped));
    await persistField(_keyVolume, clamped);
  }

  Future<void> setSeekForwardSeconds(int seconds) async {
    final clamped = seconds.clamp(5, 120);
    final current = state.value ?? const PlayerSettingsState();
    state = AsyncValue.data(current.copyWith(seekForwardSeconds: clamped));
    await persistField(_keySeekForward, clamped);
  }

  Future<void> setSeekBackwardSeconds(int seconds) async {
    final clamped = seconds.clamp(5, 120);
    final current = state.value ?? const PlayerSettingsState();
    state = AsyncValue.data(current.copyWith(seekBackwardSeconds: clamped));
    await persistField(_keySeekBackward, clamped);
  }

  Future<void> setKeyboardHoldLeftSpeed(double v) async {
    final normalized = _normalizeSpeed(v, 0.5);
    final current = state.value ?? const PlayerSettingsState();
    state = AsyncValue.data(
      current.copyWith(keyboardHoldLeftSpeed: normalized),
    );
    await persistField(_keyKbdHoldLeft, normalized);
  }

  Future<void> setKeyboardHoldRightSpeed(double v) async {
    final normalized = _normalizeSpeed(v, 3.0);
    final current = state.value ?? const PlayerSettingsState();
    state = AsyncValue.data(
      current.copyWith(keyboardHoldRightSpeed: normalized),
    );
    await persistField(_keyKbdHoldRight, normalized);
  }

  Future<void> setMouseLeftClickAction(GestureAction a) async {
    final current = state.value ?? const PlayerSettingsState();
    state = AsyncValue.data(current.copyWith(mouseLeftClickAction: a));
    await persistField(_keyMouseLeftClick, a.name);
  }

  Future<void> setMouseLeftDoubleClickAction(GestureAction a) async {
    final current = state.value ?? const PlayerSettingsState();
    state = AsyncValue.data(current.copyWith(mouseLeftDoubleClickAction: a));
    await persistField(_keyMouseLeftDblClick, a.name);
  }

  Future<void> setMouseRightClickAction(GestureAction a) async {
    final current = state.value ?? const PlayerSettingsState();
    state = AsyncValue.data(current.copyWith(mouseRightClickAction: a));
    await persistField(_keyMouseRightClick, a.name);
  }

  Future<void> setMouseRightDoubleClickAction(GestureAction a) async {
    final current = state.value ?? const PlayerSettingsState();
    state = AsyncValue.data(current.copyWith(mouseRightDoubleClickAction: a));
    await persistField(_keyMouseRightDblClick, a.name);
  }

  Future<void> setAndroidBrightness(double brightness) async {
    final clamped = brightness.clamp(0.0, 1.0);
    final current = state.value ?? const PlayerSettingsState();
    state = AsyncValue.data(current.copyWith(androidBrightness: clamped));
    await persistField(_keyAndroidBrightness, clamped);
  }
}

final playerSettingsProvider =
    AsyncNotifierProvider<PlayerSettingsNotifier, PlayerSettingsState>(
      PlayerSettingsNotifier.new,
    );
