// ============================================================
// AuthProvider — 认证状态 Riverpod Provider
//
// 管理 App 全局登录状态，替代原有的 ValueNotifier<AuthResult?> 模式。
// 所有页面通过 ref.watch(authStateProvider) 感知认证状态变化。
// ============================================================

import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../domain/entities/auth_user.dart';
import '../../domain/entities/auth_session.dart';
import '../../domain/repositories/auth_repository.dart';
import '../../data/repositories/auth_repository_impl.dart';

// ── Repository Provider ───────────────────────────────────────

final authRepositoryProvider = Provider<IAuthRepository>((ref) {
  return AuthRepositoryImpl();
});

// ── Auth State ────────────────────────────────────────────────

class AuthState {
  final AuthUser? user;
  final String? accessToken;
  final String? refreshToken;
  final bool isLoading;
  final String? error;

  const AuthState({
    this.user,
    this.accessToken,
    this.refreshToken,
    this.isLoading = false,
    this.error,
  });

  bool get isAuthenticated => user != null && accessToken != null;

  const AuthState.initial() : this(isLoading: false);

  AuthState copyWith({
    AuthUser? user,
    String? accessToken,
    String? refreshToken,
    bool? isLoading,
    String? error,
    bool clearUser = false,
    bool clearError = false,
  }) {
    return AuthState(
      user: clearUser ? null : (user ?? this.user),
      accessToken: clearUser ? null : (accessToken ?? this.accessToken),
      refreshToken: clearUser ? null : (refreshToken ?? this.refreshToken),
      isLoading: isLoading ?? this.isLoading,
      error: clearError ? null : (error ?? this.error),
    );
  }
}

// ── Auth Notifier ─────────────────────────────────────────────

class AuthNotifier extends Notifier<AuthState> {
  @override
  AuthState build() => const AuthState.initial();

  IAuthRepository get _repo => ref.read(authRepositoryProvider);

  /// 从 AuthSession 更新状态
  void _setSession(AuthSession session) {
    state = AuthState(
      user: session.user,
      accessToken: session.accessToken,
      refreshToken: session.refreshToken,
    );
  }

  /// Session 过期时由 ApiClient 回调触发（配合 main.dart 中的监听）
  void onSessionExpired() {
    state = const AuthState.initial();
  }

  // ── 会话恢复 ───────────────────────────────────────────────

  Future<bool> restoreSession() async {
    state = state.copyWith(isLoading: true, clearError: true);
    try {
      final session = await _repo.restoreSession();
      if (session != null) {
        _setSession(session);
        return true;
      }
      state = state.copyWith(isLoading: false, clearUser: true);
      return false;
    } catch (e) {
      state = state.copyWith(isLoading: false, clearUser: true);
      return false;
    }
  }

  // ── 密码登录 ──────────────────────────────────────────────

  Future<void> loginByPassword({
    required String identifier,
    required String password,
    String? deviceInfo,
  }) async {
    state = state.copyWith(isLoading: true, clearError: true);
    try {
      final session = await _repo.loginByPassword(
        identifier: identifier,
        password: password,
        deviceInfo: deviceInfo,
      );
      _setSession(session);
    } catch (e) {
      state = state.copyWith(isLoading: false, error: _extractMessage(e));
      rethrow;
    }
  }

  // ── SMS 验证码登录 ────────────────────────────────────────

  Future<void> loginByPhone({
    required String phone,
    required String smsCode,
    String? deviceInfo,
  }) async {
    state = state.copyWith(isLoading: true, clearError: true);
    try {
      final session = await _repo.loginByPhone(
        phone: phone,
        smsCode: smsCode,
        deviceInfo: deviceInfo,
      );
      _setSession(session);
    } catch (e) {
      state = state.copyWith(isLoading: false, error: _extractMessage(e));
      rethrow;
    }
  }

  // ── 邮件验证码登录 ────────────────────────────────────────

  Future<void> loginByEmail({required String email, required String emailCode}) async {
    state = state.copyWith(isLoading: true, clearError: true);
    try {
      final session = await _repo.loginByEmail(email: email, emailCode: emailCode);
      _setSession(session);
    } catch (e) {
      state = state.copyWith(isLoading: false, error: _extractMessage(e));
      rethrow;
    }
  }

  // ── 第三方登录 ────────────────────────────────────────────

  Future<void> loginByWechat({required String code, String? referralCode}) async {
    state = state.copyWith(isLoading: true, clearError: true);
    try {
      final session = await _repo.loginByWechat(code: code, referralCode: referralCode);
      _setSession(session);
    } catch (e) {
      state = state.copyWith(isLoading: false, error: _extractMessage(e));
      rethrow;
    }
  }

  Future<void> loginByAlipay({required String authCode, String? referralCode}) async {
    state = state.copyWith(isLoading: true, clearError: true);
    try {
      final session = await _repo.loginByAlipay(authCode: authCode, referralCode: referralCode);
      _setSession(session);
    } catch (e) {
      state = state.copyWith(isLoading: false, error: _extractMessage(e));
      rethrow;
    }
  }

  Future<void> loginByGoogle({required String idToken, String? referralCode}) async {
    state = state.copyWith(isLoading: true, clearError: true);
    try {
      final session = await _repo.loginByGoogle(idToken: idToken, referralCode: referralCode);
      _setSession(session);
    } catch (e) {
      state = state.copyWith(isLoading: false, error: _extractMessage(e));
      rethrow;
    }
  }

  Future<void> loginByApple({
    required String identityToken,
    String? displayName,
    String? referralCode,
  }) async {
    state = state.copyWith(isLoading: true, clearError: true);
    try {
      final session = await _repo.loginByApple(
        identityToken: identityToken,
        displayName: displayName,
        referralCode: referralCode,
      );
      _setSession(session);
    } catch (e) {
      state = state.copyWith(isLoading: false, error: _extractMessage(e));
      rethrow;
    }
  }

  // ── 注册 ──────────────────────────────────────────────────

  Future<void> register({
    required String phone,
    required String smsCode,
    required String password,
    String? nickname,
    String? referralCode,
  }) async {
    state = state.copyWith(isLoading: true, clearError: true);
    try {
      final session = await _repo.register(
        phone: phone,
        smsCode: smsCode,
        password: password,
        nickname: nickname,
        referralCode: referralCode,
      );
      _setSession(session);
    } catch (e) {
      state = state.copyWith(isLoading: false, error: _extractMessage(e));
      rethrow;
    }
  }

  Future<void> registerByEmail({
    required String email,
    required String emailCode,
    required String password,
    String? nickname,
    String? referralCode,
  }) async {
    state = state.copyWith(isLoading: true, clearError: true);
    try {
      final session = await _repo.registerByEmail(
        email: email,
        emailCode: emailCode,
        password: password,
        nickname: nickname,
        referralCode: referralCode,
      );
      _setSession(session);
    } catch (e) {
      state = state.copyWith(isLoading: false, error: _extractMessage(e));
      rethrow;
    }
  }

  // ── 登出 ──────────────────────────────────────────────────

  Future<void> logout() async {
    await _repo.logout();
    state = const AuthState.initial();
  }

  // ── 验证码 ────────────────────────────────────────────────

  Future<int> sendSmsCode(String phone, SmsCodeType type) =>
      _repo.sendSmsCode(phone, type);

  Future<int> sendEmailCode(String email, EmailCodeType type) =>
      _repo.sendEmailCode(email, type);

  // ── 推荐码验证 ────────────────────────────────────────────

  Future<bool> validateReferralCode(String code) =>
      _repo.validateReferralCode(code);

  // ── 密码管理 ──────────────────────────────────────────────

  Future<void> resetPassword({
    required String phone,
    required String smsCode,
    required String newPassword,
  }) =>
      _repo.resetPassword(phone: phone, smsCode: smsCode, newPassword: newPassword);

  Future<void> resetPasswordByEmail({
    required String email,
    required String emailCode,
    required String newPassword,
  }) =>
      _repo.resetPasswordByEmail(
        email: email,
        emailCode: emailCode,
        newPassword: newPassword,
      );

  Future<void> changePassword({
    required String oldPassword,
    required String newPassword,
  }) =>
      _repo.changePassword(oldPassword: oldPassword, newPassword: newPassword);

  Future<String> getAlipayAuthString() => _repo.getAlipayAuthString();

  // ── 私有工具 ──────────────────────────────────────────────

  String _extractMessage(Object e) {
    final str = e.toString();
    // DioException 格式: "DioException [...]: message"
    final match = RegExp(r'message["\s:]+([^"}\n]+)').firstMatch(str);
    return match?.group(1)?.trim() ?? str;
  }
}

// ── Provider 导出 ─────────────────────────────────────────────

final authProvider = NotifierProvider<AuthNotifier, AuthState>(AuthNotifier.new);

/// 便捷选择器：当前登录用户（null = 未登录）
final currentUserProvider = Provider<AuthUser?>((ref) {
  return ref.watch(authProvider).user;
});

/// 便捷选择器：是否已登录
final isAuthenticatedProvider = Provider<bool>((ref) {
  return ref.watch(authProvider).isAuthenticated;
});
