import 'dart:convert';

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:flutter_timezone/flutter_timezone.dart';

import '../api/endpoints/me.dart';
import '../library/library_providers.dart' show dioProvider;
import '../models/user.dart';

const _kServerUrl       = 'server_url';
const _kSessionToken    = 'session_token';
const _kCurrentUser     = 'current_user';
const _kTzLastSentAt    = 'tz_last_sent_at';
const _weeklyMs         = 7 * 24 * 60 * 60 * 1000;

final secureStorageProvider = Provider<FlutterSecureStorage>(
  (ref) => const FlutterSecureStorage(),
);

final serverUrlProvider = FutureProvider<String?>((ref) async {
  return ref.watch(secureStorageProvider).read(key: _kServerUrl);
});

final sessionTokenProvider = FutureProvider<String?>((ref) async {
  return ref.watch(secureStorageProvider).read(key: _kSessionToken);
});

class AuthController extends AsyncNotifier<User?> {
  late FlutterSecureStorage _storage;

  @override
  Future<User?> build() async {
    _storage = ref.watch(secureStorageProvider);
    final raw = await _storage.read(key: _kCurrentUser);
    if (raw == null) return null;
    final user = User.fromJson(jsonDecode(raw) as Map<String, dynamic>);
    // Fire-and-forget timezone send on app start with an existing
    // session — no-op when last_sent_at is fresh.
    // ignore: unawaited_futures
    _sendTimezoneIfStale();
    return user;
  }

  Future<void> setServerUrl(String url) async {
    await _storage.write(key: _kServerUrl, value: url);
    ref.invalidate(serverUrlProvider);
  }

  Future<void> setSession({required String token, required String userJson}) async {
    await _storage.write(key: _kSessionToken, value: token);
    await _storage.write(key: _kCurrentUser,  value: userJson);
    ref.invalidate(sessionTokenProvider);
    state = AsyncData(User.fromJson(jsonDecode(userJson) as Map<String, dynamic>));
    // ignore: unawaited_futures
    _sendTimezoneIfStale();
  }

  Future<void> clearSession() async {
    await _storage.delete(key: _kSessionToken);
    await _storage.delete(key: _kCurrentUser);
    ref.invalidate(sessionTokenProvider);
    state = const AsyncData(null);
  }

  /// Sends the device's current IANA timezone to PUT /api/me/timezone
  /// when the last successful send was >7 days ago (or never).
  /// Cadence persists in flutter_secure_storage so it survives app
  /// restarts. Failures are swallowed: the server keeps its previous
  /// value (or 'UTC' default) until the next attempt.
  Future<void> _sendTimezoneIfStale() async {
    try {
      final lastStr = await _storage.read(key: _kTzLastSentAt);
      final lastMs = lastStr == null ? 0 : int.tryParse(lastStr) ?? 0;
      final nowMs = DateTime.now().millisecondsSinceEpoch;
      if (nowMs - lastMs < _weeklyMs) return;
      final tz = await FlutterTimezone.getLocalTimezone();
      if (tz.isEmpty) return;
      final dio = await ref.read(dioProvider.future);
      await MeApi(dio).putTimezone(tz);
      await _storage.write(key: _kTzLastSentAt, value: nowMs.toString());
    } catch (_) {
      // Non-fatal — server falls back to UTC or last-known value.
    }
  }
}

final authControllerProvider =
    AsyncNotifierProvider<AuthController, User?>(AuthController.new);
