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

import '../../core/network/dio_client.dart';
import '../services/auth_service.dart';

export '../services/auth_service.dart'
    show CheckAccountForRegisterResult, LoginResult;

const _kToken = 'auth_token';
const _kUid = 'auth_uid';
const _kEmail = 'auth_email';

/// 认证仓库：持久化 Token，对外暴露登录状态
class AuthRepository {
  const AuthRepository(this._service, this._storage);

  final AuthService _service;
  final FlutterSecureStorage _storage;

  // ── Token 读写 ──────────────────────────────────────────

  Future<String?> getToken() => _storage.read(key: _kToken);

  Future<bool> get isLoggedIn async {
    final token = await _storage.read(key: _kToken);
    return token != null && token.isNotEmpty;
  }

  Future<void> _saveSession(LoginResult result) async {
    await Future.wait([
      _storage.write(key: _kToken, value: result.token),
      if (result.uid != null) _storage.write(key: _kUid, value: result.uid!),
      if (result.email != null)
        _storage.write(key: _kEmail, value: result.email!),
    ]);
    updateCachedToken(result.token); // 同步更新内存缓存
  }

  /// 清除本地登录态（session 过期时直接调用，不请求接口）
  Future<void> clearSession() => _clearSession();

  Future<void> _clearSession() async {
    updateCachedToken(null); // 立即清除内存缓存，防止并发请求带旧 token
    await Future.wait([
      _storage.delete(key: _kToken),
      _storage.delete(key: _kUid),
      _storage.delete(key: _kEmail),
    ]);
  }

  // ── 登录流程 ────────────────────────────────────────────

  /// 登录发码前校验密码
  Future<void> checkLoginPassword({
    required String email,
    required String password,
  }) =>
      _service.checkLoginPassword(username: email, password: password);

  /// 注册发码前校验账号是否已存在
  Future<CheckAccountForRegisterResult> checkAccountForRegister(
    String email,
  ) =>
      _service.checkAccountForRegister(email);

  /// 发送登录邮箱验证码
  Future<void> sendLoginCode(String email) =>
      _service.sendLoginEmailCode(email);

  /// 密码+验证码登录
  Future<LoginResult> loginWithPassword({
    required String email,
    required String password,
    required String code,
    String vtype = '2',
  }) async {
    final result = await _service.loginWithPassword(
      email: email,
      password: password,
      code: code,
      vtype: vtype,
    );
    await _saveSession(result);
    return result;
  }

  // ── 注册流程 ────────────────────────────────────────────

  /// 发送注册邮箱验证码
  Future<void> sendRegisterCode(String email) =>
      _service.sendRegisterEmailCode(email);

  /// 邮箱注册
  Future<void> registerWithEmail({
    required String email,
    required String password,
    required String code,
    String? inviteCode,
  }) async {
    await _service.registerWithEmail(
      email: email,
      password: password,
      code: code,
      inviteCode: inviteCode,
    );
  }

  // ── 忘记密码流程 ────────────────────────────────────────

  /// 发送重置密码邮箱验证码
  Future<void> sendResetCode(String email) =>
      _service.sendResetEmailCode(email);

  /// 重置密码
  Future<void> resetPassword({
    required String email,
    required String password,
    required String code,
  }) async {
    await _service.resetPassword(
      email: email,
      password: password,
      code: code,
    );
  }

  // ── 退出登录 ────────────────────────────────────────────

  Future<void> logout() async {
    // 先清除本地 token，防止 logout 接口返回 4000 时 Dio 拦截器误触发过期弹窗
    await _clearSession();
    try {
      await _service.logout();
    } catch (_) {
      // 接口失败不影响本地登出（token 可能已过期）
    }
  }

  /// 读取登录时保存在本地的 uid（登录时必定写入，可作可靠兜底）
  Future<String?> getSavedUid() => _storage.read(key: _kUid);

  // ── 获取用户信息 ────────────────────────────────────────

  Future<Map<String, dynamic>> getMyInfo() => _service.getMyInfo();
}

// ── Providers ──────────────────────────────────────────────

final authServiceProvider = Provider<AuthService>((ref) {
  final dio = ref.watch(dioClientProvider);
  return AuthService(dio);
});

final authRepositoryProvider = Provider<AuthRepository>((ref) {
  final service = ref.watch(authServiceProvider);
  final storage = ref.watch(secureStorageProvider);
  return AuthRepository(service, storage);
});
