import 'package:flutter/foundation.dart';
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:real_estate_mobile/core/network/api_client.dart';
import 'package:real_estate_mobile/core/network/api_exceptions.dart';
import 'package:real_estate_mobile/core/services/push_notification_service.dart';
import 'package:real_estate_mobile/core/storage/secure_storage.dart';
import 'package:real_estate_mobile/features/auth/data/auth_repository.dart';
import 'package:real_estate_mobile/features/auth/data/models/register_request.dart';
import 'package:real_estate_mobile/features/auth/data/models/user_model.dart';
import 'package:real_estate_mobile/features/messaging/data/socket_service.dart';

// Auth state
enum AuthStatus { initial, loading, authenticated, error }

class AuthState {
  final AuthStatus status;
  final UserModel? user;
  final String? errorMessage;
  final List<FieldError> fieldErrors;
  final String registeredEmail;
  final bool requiresTwoFactor;
  final String? tempToken;
  final String? twoFactorEmail;
  final bool registrationSuccess;

  const AuthState({
    this.status = AuthStatus.initial,
    this.user,
    this.errorMessage,
    this.fieldErrors = const [],
    this.registeredEmail = '',
    this.requiresTwoFactor = false,
    this.tempToken,
    this.twoFactorEmail,
    this.registrationSuccess = false,
  });

  AuthState copyWith({
    AuthStatus? status,
    UserModel? user,
    String? errorMessage,
    List<FieldError>? fieldErrors,
    String? registeredEmail,
    bool? requiresTwoFactor,
    String? tempToken,
    String? twoFactorEmail,
    bool? registrationSuccess,
  }) {
    return AuthState(
      status: status ?? this.status,
      user: user ?? this.user,
      errorMessage: errorMessage,
      fieldErrors: fieldErrors ?? this.fieldErrors,
      registeredEmail: registeredEmail ?? this.registeredEmail,
      requiresTwoFactor: requiresTwoFactor ?? this.requiresTwoFactor,
      tempToken: tempToken ?? this.tempToken,
      twoFactorEmail: twoFactorEmail ?? this.twoFactorEmail,
      registrationSuccess: registrationSuccess ?? this.registrationSuccess,
    );
  }

  String? getFieldError(String fieldName) {
    final match = fieldErrors.where((e) => e.field == fieldName);
    if (match.isEmpty) return null;
    return match.first.errors.isNotEmpty ? match.first.errors.first : null;
  }
}

// Auth notifier
class AuthNotifier extends StateNotifier<AuthState> {
  final AuthRepository _repository;

  AuthNotifier(this._repository)
      : super(const AuthState(status: AuthStatus.loading)) {
    // Wire up force logout callback so API client can reset auth state
    // when token refresh fails
    ApiClient.onForceLogout = () {
      SocketService().disconnect();
      // Delete local FCM token so push notifications stop
      PushNotificationService().unregister();
      // Only reset if still authenticated — avoid showing errors on login screen
      if (state.status == AuthStatus.authenticated) {
        state = const AuthState();
      }
    };
    checkAuthStatus();
  }

  Future<void> checkAuthStatus() async {
    state = state.copyWith(status: AuthStatus.loading);

    final token = await SecureStorage.getAccessToken();
    if (token == null) {
      state = state.copyWith(status: AuthStatus.initial);
      return;
    }

    try {
      final user = await _repository.getMe();
      // Re-enable auth error handling after successful login
      ApiClient.suppressAuthErrors = false;
      state = state.copyWith(
        status: AuthStatus.authenticated,
        user: user,
      );
      // Connect socket for real-time updates (matching web's PresenceProvider)
      _connectSocket();
      // Register for push notifications after auth confirmed
      _initPushNotifications();
    } catch (_) {
      // Token is invalid/expired — clear and show login
      await SecureStorage.clearTokens();
      state = state.copyWith(status: AuthStatus.initial);
    }
  }

  Future<void> logout() async {
    // Suppress 401 errors during logout to prevent SnackBar flashing
    ApiClient.suppressAuthErrors = true;
    // Reset state first so UI navigates to login immediately
    state = const AuthState();
    // Disconnect socket immediately
    SocketService().disconnect();
    // Unregister FCM BEFORE clearing tokens — backend call needs auth header,
    // and deleteToken() stops Firebase from delivering to this device
    try {
      await PushNotificationService().unregister();
    } catch (_) {}
    // Logout API call + clear local tokens
    await _repository.logout();
  }

  Future<void> login({
    required String email,
    required String password,
    String? loginRole,
  }) async {
    // Reset suppressAuthErrors in case a prior logout left it enabled —
    // otherwise the 401 interceptor rejects errors unwrapped and we lose
    // the backend's message (e.g. role-mismatch), falling back to generic.
    ApiClient.suppressAuthErrors = false;
    state = state.copyWith(
      status: AuthStatus.loading,
      errorMessage: null,
      fieldErrors: [],
    );

    try {
      final result = await _repository.login(
        email: email,
        password: password,
        loginRole: loginRole,
      );

      if (result['requiresTwoFactor'] == true) {
        state = state.copyWith(
          status: AuthStatus.initial,
          requiresTwoFactor: true,
          tempToken: result['tempToken'] as String?,
          twoFactorEmail: email,
        );
        return;
      }

      ApiClient.suppressAuthErrors = false;
      state = state.copyWith(
        status: AuthStatus.authenticated,
        user: result['user'] as UserModel,
      );
      _connectSocket();
      _initPushNotifications();
    } on ApiException catch (e) {
      state = state.copyWith(
        status: AuthStatus.error,
        errorMessage: e.fieldErrors.isNotEmpty
            ? 'Please fix the errors below'
            : e.message,
        fieldErrors: e.fieldErrors,
      );
    } catch (e) {
      state = state.copyWith(
        status: AuthStatus.error,
        errorMessage: 'An unexpected error occurred',
      );
    }
  }

  Future<void> signInWithGoogle({
    String? role,
    String? agentTypeId,
    String mode = 'signup',
  }) async {
    state = state.copyWith(
      status: AuthStatus.loading,
      errorMessage: null,
      fieldErrors: [],
    );

    try {
      final googleSignIn = GoogleSignIn(
        scopes: ['email', 'profile'],
        serverClientId: '703616926518-9h70kp29oqdgi8umr84u6n59kpb22q97.apps.googleusercontent.com',
      );
      final account = await googleSignIn.signIn();

      if (account == null) {
        // User cancelled
        state = state.copyWith(status: AuthStatus.initial);
        return;
      }

      final user = await _repository.socialAuth(
        provider: 'google',
        providerId: account.id,
        email: account.email,
        name: account.displayName,
        avatar: account.photoUrl,
        role: role,
        agentTypeId: agentTypeId,
        mode: mode,
      );

      state = state.copyWith(
        status: AuthStatus.authenticated,
        user: user,
      );
      _connectSocket();
      _initPushNotifications();
    } on ApiException catch (e) {
      state = state.copyWith(
        status: AuthStatus.error,
        errorMessage: e.message,
      );
    } catch (e) {
      debugPrint('Google sign-in error: $e');
      state = state.copyWith(
        status: AuthStatus.error,
        errorMessage: 'Google sign-in failed. Please try again.',
      );
    }
  }

  Future<void> signInWithFacebook({
    String? role,
    String? agentTypeId,
    String mode = 'signup',
  }) async {
    state = state.copyWith(
      status: AuthStatus.loading,
      errorMessage: null,
      fieldErrors: [],
    );

    try {
      final result = await FacebookAuth.instance.login(
        permissions: ['email', 'public_profile'],
      );

      if (result.status == LoginStatus.cancelled) {
        state = state.copyWith(status: AuthStatus.initial);
        return;
      }

      if (result.status != LoginStatus.success) {
        state = state.copyWith(
          status: AuthStatus.error,
          errorMessage: result.message ?? 'Facebook login failed',
        );
        return;
      }

      final userData = await FacebookAuth.instance.getUserData(
        fields: 'id,name,email,picture.width(200)',
      );

      final email = userData['email'] as String?;
      if (email == null || email.isEmpty) {
        state = state.copyWith(
          status: AuthStatus.error,
          errorMessage: 'Email not available from Facebook. Please use email login.',
        );
        return;
      }

      final pictureData = userData['picture']?['data'];
      final avatarUrl = pictureData?['url'] as String?;

      final user = await _repository.socialAuth(
        provider: 'facebook',
        providerId: userData['id'] as String,
        email: email,
        name: userData['name'] as String?,
        avatar: avatarUrl,
        role: role,
        agentTypeId: agentTypeId,
        mode: mode,
      );

      state = state.copyWith(
        status: AuthStatus.authenticated,
        user: user,
      );
      _connectSocket();
      _initPushNotifications();
    } on ApiException catch (e) {
      state = state.copyWith(
        status: AuthStatus.error,
        errorMessage: e.message,
      );
    } catch (e) {
      debugPrint('Facebook sign-in error: $e');
      state = state.copyWith(
        status: AuthStatus.error,
        errorMessage: 'Facebook sign-in failed. Please try again.',
      );
    }
  }

  /// Complete Twitter/X login after webview returns user data.
  Future<void> completeTwitterLogin(
    Map<String, dynamic> twitterUser, {
    String? role,
    String? agentTypeId,
    String mode = 'signup',
  }) async {
    state = state.copyWith(
      status: AuthStatus.loading,
      errorMessage: null,
      fieldErrors: [],
    );

    try {
      final user = await _repository.socialAuth(
        provider: 'twitter',
        providerId: twitterUser['id'] as String,
        email: '${twitterUser['username']}@x.com',
        name: twitterUser['name'] as String?,
        avatar: twitterUser['avatar'] as String?,
        role: role,
        agentTypeId: agentTypeId,
        mode: mode,
      );

      state = state.copyWith(
        status: AuthStatus.authenticated,
        user: user,
      );
      _connectSocket();
      _initPushNotifications();
    } on ApiException catch (e) {
      state = state.copyWith(
        status: AuthStatus.error,
        errorMessage: e.message,
      );
    } catch (e) {
      debugPrint('Twitter sign-in error: $e');
      state = state.copyWith(
        status: AuthStatus.error,
        errorMessage: 'X/Twitter sign-in failed. Please try again.',
      );
    }
  }

  Future<void> register({
    required String name,
    required String email,
    required String password,
    required String role,
    String? agentTypeId,
  }) async {
    state = state.copyWith(
      status: AuthStatus.loading,
      errorMessage: null,
      fieldErrors: [],
    );

    // Split name into firstName and lastName
    final nameParts = name.trim().split(RegExp(r'\s+'));
    final firstName = nameParts.first;
    final lastName = nameParts.length > 1 ? nameParts.sublist(1).join(' ') : null;

    try {
      await _repository.register(
        RegisterRequest(
          email: email,
          password: password,
          role: role,
          firstName: firstName,
          lastName: lastName,
          agentTypeId: role == 'AGENT' ? agentTypeId : null,
        ),
      );

      // Registration successful — user must verify email before logging in
      state = state.copyWith(
        status: AuthStatus.initial,
        registeredEmail: email,
        registrationSuccess: true,
      );
    } on ApiException catch (e) {
      state = state.copyWith(
        status: AuthStatus.error,
        errorMessage: e.fieldErrors.isNotEmpty
            ? 'Please fix the errors below'
            : e.message,
        fieldErrors: e.fieldErrors,
      );
    } catch (e) {
      state = state.copyWith(
        status: AuthStatus.error,
        errorMessage: 'An unexpected error occurred',
      );
    }
  }

  Future<void> verifyTwoFactor(String token) async {
    final tempToken = state.tempToken;
    if (tempToken == null) {
      state = state.copyWith(
        errorMessage: 'Session expired. Please login again.',
      );
      return;
    }

    state = state.copyWith(
      status: AuthStatus.loading,
      errorMessage: null,
    );

    try {
      final authResponse = await _repository.verifyTwoFactor(
        tempToken: tempToken,
        token: token,
      );
      state = AuthState(
        status: AuthStatus.authenticated,
        user: authResponse.user,
      );
      _connectSocket();
      _initPushNotifications();
    } on ApiException catch (e) {
      // Preserve tempToken and requiresTwoFactor so user can retry
      state = state.copyWith(
        status: AuthStatus.initial,
        requiresTwoFactor: true,
        errorMessage: e.message,
      );
    } catch (e) {
      state = state.copyWith(
        status: AuthStatus.initial,
        requiresTwoFactor: true,
        errorMessage: 'Verification failed. Please try again.',
      );
    }
  }

  Future<void> verifyBackupCode(String backupCode) async {
    final tempToken = state.tempToken;
    if (tempToken == null) {
      state = state.copyWith(
        errorMessage: 'Session expired. Please login again.',
      );
      return;
    }

    state = state.copyWith(
      status: AuthStatus.loading,
      errorMessage: null,
    );

    try {
      final authResponse = await _repository.verifyBackupCode(
        tempToken: tempToken,
        backupCode: backupCode,
      );
      state = AuthState(
        status: AuthStatus.authenticated,
        user: authResponse.user,
      );
      _connectSocket();
      _initPushNotifications();
    } on ApiException catch (e) {
      state = state.copyWith(
        status: AuthStatus.initial,
        requiresTwoFactor: true,
        errorMessage: e.message,
      );
    } catch (e) {
      state = state.copyWith(
        status: AuthStatus.initial,
        requiresTwoFactor: true,
        errorMessage: 'Verification failed. Please try again.',
      );
    }
  }

  void clearTwoFactor() {
    state = const AuthState();
  }

  void _connectSocket() {
    SocketService().connect();
  }

  void _initPushNotifications() {
    final push = PushNotificationService();
    push.initialize().then((_) => push.registerAfterLogin());
  }

  void reset() {
    state = const AuthState();
  }
}

// Providers
final authRepositoryProvider = Provider<AuthRepository>((ref) {
  return AuthRepository();
});

final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
  return AuthNotifier(ref.watch(authRepositoryProvider));
});
