import 'package:hive_flutter/hive_flutter.dart';
import 'package:lunchpick/domain/repositories/settings_repository.dart';
import 'package:lunchpick/domain/entities/user_settings.dart';

class SettingsRepositoryImpl implements SettingsRepository {
  static const String _boxName = 'settings';

  // Setting keys
  static const String _keyDaysToExclude = 'days_to_exclude';
  static const String _keyMaxDistanceRainy = 'max_distance_rainy';
  static const String _keyMaxDistanceNormal = 'max_distance_normal';
  static const String _keyNotificationDelayMinutes =
      'notification_delay_minutes';
  static const String _keyNotificationEnabled = 'notification_enabled';
  static const String _keyScreenshotModeEnabled = 'screenshot_mode_enabled';
  static const String _keyDarkModeEnabled = 'dark_mode_enabled';
  static const String _keyFirstRun = 'first_run';
  static const String _keyCategoryWeights = 'category_weights';

  // Default values
  static const int _defaultDaysToExclude = 14;
  static const int _defaultMaxDistanceRainy = 500;
  static const int _defaultMaxDistanceNormal = 1000;
  static const int _defaultNotificationDelayMinutes = 90;
  static const bool _defaultNotificationEnabled = true;
  static const bool _defaultScreenshotModeEnabled = false;
  static const bool _defaultDarkModeEnabled = false;
  static const bool _defaultFirstRun = true;

  Future<Box> get _box async => await Hive.openBox(_boxName);

  @override
  Future<UserSettings> getUserSettings() async {
    final box = await _box;

    // 저장된 설정값들을 읽어옴
    final revisitPreventionDays = box.get(
      _keyDaysToExclude,
      defaultValue: _defaultDaysToExclude,
    );
    final notificationEnabled = box.get(
      _keyNotificationEnabled,
      defaultValue: _defaultNotificationEnabled,
    );
    final notificationDelayMinutes = box.get(
      _keyNotificationDelayMinutes,
      defaultValue: _defaultNotificationDelayMinutes,
    );

    // 카테고리 가중치 읽기 (Map<String, double>으로 저장됨)
    final categoryWeightsData = box.get(_keyCategoryWeights);
    Map<String, double> categoryWeights = {};
    if (categoryWeightsData != null) {
      categoryWeights = Map<String, double>.from(categoryWeightsData);
    }

    // 알림 시간은 분을 시간:분 형식으로 변환
    final hours = notificationDelayMinutes ~/ 60;
    final minutes = notificationDelayMinutes % 60;
    final notificationTime =
        '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}';

    return UserSettings(
      revisitPreventionDays: revisitPreventionDays,
      notificationEnabled: notificationEnabled,
      notificationTime: notificationTime,
      categoryWeights: categoryWeights,
      notificationDelayMinutes: notificationDelayMinutes,
    );
  }

  @override
  Future<void> updateUserSettings(UserSettings settings) async {
    final box = await _box;

    // 각 설정값 저장
    await box.put(_keyDaysToExclude, settings.revisitPreventionDays);
    await box.put(_keyNotificationEnabled, settings.notificationEnabled);
    await box.put(
      _keyNotificationDelayMinutes,
      settings.notificationDelayMinutes,
    );

    // 카테고리 가중치 저장
    await box.put(_keyCategoryWeights, settings.categoryWeights);
  }

  @override
  Future<int> getDaysToExclude() async {
    final box = await _box;
    return box.get(_keyDaysToExclude, defaultValue: _defaultDaysToExclude);
  }

  @override
  Future<void> setDaysToExclude(int days) async {
    final box = await _box;
    await box.put(_keyDaysToExclude, days);
  }

  @override
  Future<int> getMaxDistanceRainy() async {
    final box = await _box;
    return box.get(
      _keyMaxDistanceRainy,
      defaultValue: _defaultMaxDistanceRainy,
    );
  }

  @override
  Future<void> setMaxDistanceRainy(int meters) async {
    final box = await _box;
    await box.put(_keyMaxDistanceRainy, meters);
  }

  @override
  Future<int> getMaxDistanceNormal() async {
    final box = await _box;
    return box.get(
      _keyMaxDistanceNormal,
      defaultValue: _defaultMaxDistanceNormal,
    );
  }

  @override
  Future<void> setMaxDistanceNormal(int meters) async {
    final box = await _box;
    await box.put(_keyMaxDistanceNormal, meters);
  }

  @override
  Future<int> getNotificationDelayMinutes() async {
    final box = await _box;
    return box.get(
      _keyNotificationDelayMinutes,
      defaultValue: _defaultNotificationDelayMinutes,
    );
  }

  @override
  Future<void> setNotificationDelayMinutes(int minutes) async {
    final box = await _box;
    await box.put(_keyNotificationDelayMinutes, minutes);
  }

  @override
  Future<bool> isNotificationEnabled() async {
    final box = await _box;
    return box.get(
      _keyNotificationEnabled,
      defaultValue: _defaultNotificationEnabled,
    );
  }

  @override
  Future<void> setNotificationEnabled(bool enabled) async {
    final box = await _box;
    await box.put(_keyNotificationEnabled, enabled);
  }

  @override
  Future<bool> isScreenshotModeEnabled() async {
    final box = await _box;
    return box.get(
      _keyScreenshotModeEnabled,
      defaultValue: _defaultScreenshotModeEnabled,
    );
  }

  @override
  Future<void> setScreenshotModeEnabled(bool enabled) async {
    final box = await _box;
    await box.put(_keyScreenshotModeEnabled, enabled);
  }

  @override
  Future<bool> isDarkModeEnabled() async {
    final box = await _box;
    return box.get(_keyDarkModeEnabled, defaultValue: _defaultDarkModeEnabled);
  }

  @override
  Future<void> setDarkModeEnabled(bool enabled) async {
    final box = await _box;
    await box.put(_keyDarkModeEnabled, enabled);
  }

  @override
  Future<bool> isFirstRun() async {
    final box = await _box;
    return box.get(_keyFirstRun, defaultValue: _defaultFirstRun);
  }

  @override
  Future<void> setFirstRun(bool isFirst) async {
    final box = await _box;
    await box.put(_keyFirstRun, isFirst);
  }

  @override
  Future<void> resetSettings() async {
    final box = await _box;
    await box.clear();

    // 기본값으로 재설정
    await box.put(_keyDaysToExclude, _defaultDaysToExclude);
    await box.put(_keyMaxDistanceRainy, _defaultMaxDistanceRainy);
    await box.put(_keyMaxDistanceNormal, _defaultMaxDistanceNormal);
    await box.put(
      _keyNotificationDelayMinutes,
      _defaultNotificationDelayMinutes,
    );
    await box.put(_keyNotificationEnabled, _defaultNotificationEnabled);
    await box.put(_keyScreenshotModeEnabled, _defaultScreenshotModeEnabled);
    await box.put(_keyDarkModeEnabled, _defaultDarkModeEnabled);
    await box.put(_keyFirstRun, false); // 리셋 후에는 첫 실행이 아님
  }

  @override
  Stream<Map<String, dynamic>> watchSettings() async* {
    final box = await _box;

    // 초기 값 전송
    yield await _getCurrentSettings();

    // 변경사항 감시
    yield* box.watch().asyncMap((_) async => await _getCurrentSettings());
  }

  Future<Map<String, dynamic>> _getCurrentSettings() async {
    return {
      _keyDaysToExclude: await getDaysToExclude(),
      _keyMaxDistanceRainy: await getMaxDistanceRainy(),
      _keyMaxDistanceNormal: await getMaxDistanceNormal(),
      _keyNotificationDelayMinutes: await getNotificationDelayMinutes(),
      _keyNotificationEnabled: await isNotificationEnabled(),
      _keyScreenshotModeEnabled: await isScreenshotModeEnabled(),
      _keyDarkModeEnabled: await isDarkModeEnabled(),
      _keyFirstRun: await isFirstRun(),
    };
  }

  @override
  Stream<UserSettings> watchUserSettings() async* {
    final box = await _box;

    // 초기 값 전송
    yield await getUserSettings();

    // 변경사항 감시
    yield* box.watch().asyncMap((_) async => await getUserSettings());
  }
}
