import 'dart:async';
import 'dart:developer' as developer;

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

import '../core/network/api_response.dart';
import '../data/repositories/auth_repository.dart';

export '../data/repositories/auth_repository.dart'
    show CheckAccountForRegisterResult, LoginResult;

// ── Enums ──────────────────────────────────────────────────

enum AuthInputMethod { email, phone }

enum LoginMode { password, code }

// ── State ──────────────────────────────────────────────────

class AuthState {
  final AuthInputMethod inputMethod;
  final LoginMode loginMode;
  final bool isLoading;
  final String? errorMessage;
  final int codeCooldown;
  final bool isLoggedIn;

  /// 注册流程暂存
  final String pendingEmail;
  final String pendingPassword;
  final String pendingInviteCode;

  /// 忘记密码流程暂存
  final bool resetMode;
  final String resetEmail;
  final String resetCode;

  const AuthState({
    this.inputMethod = AuthInputMethod.email,
    this.loginMode = LoginMode.password,
    this.isLoading = false,
    this.errorMessage,
    this.codeCooldown = 0,
    this.isLoggedIn = false,
    this.pendingEmail = '',
    this.pendingPassword = '',
    this.pendingInviteCode = '',
    this.resetMode = false,
    this.resetEmail = '',
    this.resetCode = '',
  });

  AuthState copyWith({
    AuthInputMethod? inputMethod,
    LoginMode? loginMode,
    bool? isLoading,
    String? errorMessage,
    int? codeCooldown,
    bool? isLoggedIn,
    String? pendingEmail,
    String? pendingPassword,
    String? pendingInviteCode,
    bool? resetMode,
    String? resetEmail,
    String? resetCode,
  }) =>
      AuthState(
        inputMethod: inputMethod ?? this.inputMethod,
        loginMode: loginMode ?? this.loginMode,
        isLoading: isLoading ?? this.isLoading,
        errorMessage: errorMessage,
        codeCooldown: codeCooldown ?? this.codeCooldown,
        isLoggedIn: isLoggedIn ?? this.isLoggedIn,
        pendingEmail: pendingEmail ?? this.pendingEmail,
        pendingPassword: pendingPassword ?? this.pendingPassword,
        pendingInviteCode: pendingInviteCode ?? this.pendingInviteCode,
        resetMode: resetMode ?? this.resetMode,
        resetEmail: resetEmail ?? this.resetEmail,
        resetCode: resetCode ?? this.resetCode,
      );
}

// ── Notifier ───────────────────────────────────────────────

class AuthNotifier extends Notifier<AuthState> {
  AuthRepository get _repo => ref.read(authRepositoryProvider);
  Timer? _countdownTimer;

  @override
  AuthState build() {
    ref.onDispose(() => _countdownTimer?.cancel());
    Future.microtask(_checkToken);
    return const AuthState();
  }

  Future<void> _checkToken() async {
    final loggedIn = await _repo.isLoggedIn;
    state = state.copyWith(isLoggedIn: loggedIn);
  }

  void setInputMethod(AuthInputMethod method) =>
      state = state.copyWith(inputMethod: method);

  void setLoginMode(LoginMode mode) =>
      state = state.copyWith(loginMode: mode);

  void clearError() => state = state.copyWith(errorMessage: null);

  // ── 发送验证码（带60s倒计时）──────────────────────────────

  /// 发送登录验证码（先发 `/uc/check-password` 再发码，与 Web 一致）
  Future<bool> sendLoginCode({
    required String email,
    required String password,
  }) async {
    state = state.copyWith(isLoading: true, errorMessage: null);
    try {
      await _repo.checkLoginPassword(email: email, password: password);
      await _repo.sendLoginCode(email);
      state = state.copyWith(isLoading: false);
      startCountdown();
      return true;
    } catch (e) {
      state = state.copyWith(
        isLoading: false,
        errorMessage: _loginCredentialCheckError(e),
      );
      return false;
    }
  }

  /// 发送注册验证码（先 `/uc/check-account`：已注册则拦截，与 Web 一致）
  Future<bool> sendRegisterCode({required String email}) async {
    state = state.copyWith(isLoading: true, errorMessage: null);
    try {
      final check = await _repo.checkAccountForRegister(email);
      if (check == CheckAccountForRegisterResult.alreadyRegistered) {
        state = state.copyWith(
          isLoading: false,
          errorMessage: 'errAccountAlreadyRegistered',
        );
        return false;
      }
      await _repo.sendRegisterCode(email);
      state = state.copyWith(isLoading: false);
      startCountdown();
      return true;
    } catch (e) {
      state = state.copyWith(
        isLoading: false,
        errorMessage: _parseError(e),
      );
      return false;
    }
  }

  /// 发送重置密码验证码
  Future<bool> sendResetCode({required String email}) async {
    state = state.copyWith(isLoading: true, errorMessage: null);
    try {
      await _repo.sendResetCode(email);
      state = state.copyWith(isLoading: false);
      startCountdown();
      return true;
    } catch (e) {
      state = state.copyWith(
        isLoading: false,
        errorMessage: _parseError(e),
      );
      return false;
    }
  }

  void startCountdown() {
    _countdownTimer?.cancel();
    state = state.copyWith(codeCooldown: 60);
    _countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
      final remaining = state.codeCooldown - 1;
      state = state.copyWith(codeCooldown: remaining);
      if (remaining <= 0) {
        timer.cancel();
        _countdownTimer = null;
      }
    });
  }

  // ── 登录（密码+验证码）──────────────────────────────────

  /// [vtype] 2=邮箱验证码, 3=谷歌验证码
  Future<bool> login({
    required String email,
    required String password,
    required String code,
    String vtype = '2',
  }) async {
    state = state.copyWith(isLoading: true, errorMessage: null);
    try {
      await _repo.loginWithPassword(
        email: email,
        password: password,
        code: code,
        vtype: vtype,
      );
      state = state.copyWith(isLoading: false, isLoggedIn: true);
      return true;
    } catch (e) {
      state = state.copyWith(
        isLoading: false,
        errorMessage: _parseError(e),
      );
      return false;
    }
  }

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

  /// 暂存注册信息（步骤一）
  void setPendingRegister({
    required String email,
    required String password,
    String inviteCode = '',
  }) {
    state = state.copyWith(
      pendingEmail: email,
      pendingPassword: password,
      pendingInviteCode: inviteCode,
    );
  }

  /// 提交注册（步骤二：填完验证码后调用）
  Future<bool> register({required String code}) async {
    state = state.copyWith(isLoading: true, errorMessage: null);
    try {
      await _repo.registerWithEmail(
        email: state.pendingEmail,
        password: state.pendingPassword,
        code: code,
        inviteCode: state.pendingInviteCode.isEmpty
            ? null
            : state.pendingInviteCode,
      );
      state = state.copyWith(isLoading: false);
      return true;
    } catch (e) {
      state = state.copyWith(
        isLoading: false,
        errorMessage: _parseError(e),
      );
      return false;
    }
  }

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

  /// 暂存重置密码信息
  void setPendingReset({
    required String email,
    required String code,
  }) {
    state = state.copyWith(
      resetMode: true,
      resetEmail: email,
      resetCode: code,
    );
  }

  /// 重置密码
  Future<bool> resetPassword({required String password}) async {
    state = state.copyWith(isLoading: true, errorMessage: null);
    try {
      await _repo.resetPassword(
        email: state.resetEmail,
        password: password,
        code: state.resetCode,
      );
      state = state.copyWith(
        isLoading: false,
        resetMode: false,
        resetEmail: '',
        resetCode: '',
      );
      return true;
    } catch (e) {
      state = state.copyWith(
        isLoading: false,
        errorMessage: _parseError(e),
      );
      return false;
    }
  }

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

  Future<void> logout() async {
    await _repo.logout();
    state = state.copyWith(isLoggedIn: false);
  }

  /// 仅清除本地登录态，不请求 logout 接口（用于 session 过期场景）
  Future<void> clearLocalSession() async {
    await _repo.clearSession();
    state = state.copyWith(isLoggedIn: false);
  }

  /// 与 Web 一致：校验失败时统一提示，不区分账号或密码
  String _loginCredentialCheckError(Object e) {
    if (e is DioException && e.error is ApiException) {
      return 'errLoginCredentialWrong';
    }
    if (e is ApiException) {
      return 'errLoginCredentialWrong';
    }
    return _parseError(e);
  }

  String _parseError(Object e) {
    developer.log('Auth error: $e', name: 'AUTH', error: e);

    // DioException 包裹的 ApiException
    if (e is DioException) {
      final responseData = e.response?.data;
      developer.log('Response data: $responseData', name: 'AUTH');

      if (e.error is ApiException) {
        return (e.error as ApiException).message;
      }
      // 直接从 response body 取 message/msg
      if (responseData is Map<String, dynamic>) {
        final msg = responseData['message'] as String?
            ?? responseData['msg'] as String?;
        if (msg != null && msg.isNotEmpty) return msg;
      }
      return e.message ?? 'errNetworkError';
    }

    if (e is ApiException) return e.message;

    return e.toString();
  }
}

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

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

/// 供 GoRouter 使用的登录状态 Provider
final isLoggedInProvider = Provider<bool>((ref) {
  return ref.watch(authProvider).isLoggedIn;
});
