import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';

import '../domain/auth_models.dart';

class AuthSessionStore {
  const AuthSessionStore();

  static const _tokenKey = 'tdc114plus.auth.token';
  static const _expiresAtKey = 'tdc114plus.auth.expiresAt';
  static const _userKey = 'tdc114plus.auth.user';
  static const _pendingRefKey = 'tdc114plus.auth.pending.ref';
  static const _pendingExpiresAtKey = 'tdc114plus.auth.pending.expiresAt';
  static const _pendingResendAfterAtKey =
      'tdc114plus.auth.pending.resendAfterAt';
  static const _pendingPollIntervalKey =
      'tdc114plus.auth.pending.pollInterval';
  static const _pendingProviderKey = 'tdc114plus.auth.pending.provider';

  Future<void> save(PhoneLoginResponse response) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString(_tokenKey, response.token);
    await prefs.setString(
      _expiresAtKey,
      response.expiresAt.toUtc().toIso8601String(),
    );
    await prefs.setString(_userKey, jsonEncode(response.user.toJson()));
    debugPrint(
      'AuthSessionStore.save token=${response.token} tokenLength=${response.token.length} expiresAt=${response.expiresAt.toUtc().toIso8601String()}',
    );
  }

  Future<void> savePendingLink(PhoneLoginLinkInitResponse response) async {
    final prefs = await SharedPreferences.getInstance();
    final now = DateTime.now().toUtc();
    await prefs.setString(_pendingRefKey, response.pendingRef);
    await prefs.setString(
      _pendingExpiresAtKey,
      now.add(Duration(seconds: response.expiresIn)).toIso8601String(),
    );
    await prefs.setString(
      _pendingResendAfterAtKey,
      now.add(Duration(seconds: response.resendAfter)).toIso8601String(),
    );
    await prefs.setInt(_pendingPollIntervalKey, response.interval);
    final provider = response.provider;
    if (provider == null || provider.trim().isEmpty) {
      await prefs.remove(_pendingProviderKey);
    } else {
      await prefs.setString(_pendingProviderKey, provider);
    }
  }

  Future<PhoneLoginLinkInitResponse?> loadPendingLink() async {
    final prefs = await SharedPreferences.getInstance();
    final pendingRef = prefs.getString(_pendingRefKey);
    final expiresAtValue = prefs.getString(_pendingExpiresAtKey);
    if (pendingRef == null ||
        pendingRef.trim().isEmpty ||
        expiresAtValue == null) {
      return null;
    }

    final now = DateTime.now().toUtc();
    final expiresAt = DateTime.tryParse(expiresAtValue)?.toUtc();
    if (expiresAt == null || !expiresAt.isAfter(now)) {
      await clearPendingLink();
      return null;
    }

    final resendAfterAt = DateTime.tryParse(
      prefs.getString(_pendingResendAfterAtKey) ?? '',
    )?.toUtc();
    final expiresIn = expiresAt.difference(now).inSeconds;
    final resendAfter = resendAfterAt == null || !resendAfterAt.isAfter(now)
        ? 0
        : resendAfterAt.difference(now).inSeconds;
    return PhoneLoginLinkInitResponse(
      status: 'pending',
      pendingRef: pendingRef,
      expiresIn: expiresIn,
      interval: prefs.getInt(_pendingPollIntervalKey) ?? 3,
      resendAfter: resendAfter,
      provider: prefs.getString(_pendingProviderKey),
    );
  }

  Future<void> clearPendingLink() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove(_pendingRefKey);
    await prefs.remove(_pendingExpiresAtKey);
    await prefs.remove(_pendingResendAfterAtKey);
    await prefs.remove(_pendingPollIntervalKey);
    await prefs.remove(_pendingProviderKey);
  }

  Future<StoredAuthSession?> load() async {
    final prefs = await SharedPreferences.getInstance();
    final token = prefs.getString(_tokenKey);
    final expiresAtValue = prefs.getString(_expiresAtKey);
    final userValue = prefs.getString(_userKey);
    if (token == null || expiresAtValue == null || userValue == null) {
      debugPrint(
        'AuthSessionStore.load missing token=${token != null} expiresAt=${expiresAtValue != null} user=${userValue != null}',
      );
      return null;
    }
    final session = StoredAuthSession(
      token: token,
      expiresAt: DateTime.parse(expiresAtValue),
      user: LoginUser.fromJson(jsonDecode(userValue) as Map<String, dynamic>),
    );
    debugPrint(
      'AuthSessionStore.load token=${session.token} tokenLength=${session.token.length} expiresAt=${session.expiresAt.toUtc().toIso8601String()} expired=${session.isExpired}',
    );
    return session;
  }

  Future<void> clear() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove(_tokenKey);
    await prefs.remove(_expiresAtKey);
    await prefs.remove(_userKey);
    await clearPendingLink();
    debugPrint('AuthSessionStore.clear');
  }
}

class StoredAuthSession {
  const StoredAuthSession({
    required this.token,
    required this.expiresAt,
    required this.user,
  });

  final String token;
  final DateTime expiresAt;
  final LoginUser user;

  bool get isExpired => !expiresAt.isAfter(DateTime.now().toUtc());
}

final authSessionStoreProvider = Provider<AuthSessionStore>((ref) {
  return const AuthSessionStore();
});
