import 'package:flutter/foundation.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:get/get.dart'; import 'package:google_sign_in/google_sign_in.dart'; import 'package:supabase_flutter/supabase_flutter.dart'; /// Ember által olvasható hitelesítési hiba. class AuthServiceException implements Exception { final String message; AuthServiceException(this.message); @override String toString() => message; } /// Hitelesítési service — google_sign_in 7.x + Supabase. /// /// Folyamat: natív Google bejelentkezés → idToken (+ accessToken az /// authorizationClient-ből) → Supabase signInWithIdToken → Supabase /// session (amit a supabase_flutter magától perzisztál és frissít, ezért /// app-újraindításnál NEM kell újra Google-bejelentkezés). /// /// FONTOS (google_sign_in 7.x változások a 6.x-hez képest): /// * singleton: GoogleSignIn.instance (nincs konstruktor-példányosítás) /// * kötelező egyszeri initialize() minden más hívás előtt /// * signIn() helyett authenticate(); a megszakítást kivétel jelzi /// * az authentication már csak idToken-t ad; accessToken a /// authorizationClient-től kérhető /// /// A GetX-minta szerint az állapot Rx-ekben él: a UI (drawer-fejléc, /// beállítások) Obx-szel figyeli a currentUser-t. class AuthService extends GetxService { static AuthService get to => Get.find(); SupabaseClient get _supabase => Supabase.instance.client; // ── Reaktív állapot ────────────────────────────────────────────── final currentUser = Rxn(); final isBusy = false.obs; bool get isSignedIn => currentUser.value != null; String get displayName { final u = currentUser.value; if (u == null) return 'Nincs bejelentkezve'; return (u.userMetadata?['full_name'] as String?) ?? (u.userMetadata?['name'] as String?) ?? u.email ?? 'Felhasználó'; } String get email => currentUser.value?.email ?? ''; String? get avatarUrl => currentUser.value?.userMetadata?['avatar_url'] as String?; bool _googleInitialized = false; @override void onInit() { super.onInit(); // A Supabase a sessiont maga perzisztálja — induláskor csak átvesszük. currentUser.value = _supabase.auth.currentUser; // Minden auth-változás (bejelentkezés, kijelentkezés, token-frissítés) // ide fut be; a UI a currentUser-en keresztül reagál. _supabase.auth.onAuthStateChange.listen((data) { currentUser.value = data.session?.user; }); } /// Egyszeri google_sign_in inicializálás (a 7.x megköveteli). /// A serverClientId a Supabase-ben engedélyezett WEB client ID — /// az idToken "közönsége" (aud) így egyezik a Supabase elvárásával. Future _ensureGoogleInitialized() async { if (_googleInitialized) return; final webClientId = dotenv.env['GOOGLE_WEB_CLIENT_ID']; if (webClientId == null || webClientId.isEmpty) { throw AuthServiceException( 'Hiányzó GOOGLE_WEB_CLIENT_ID a .env fájlból.'); } await GoogleSignIn.instance.initialize(serverClientId: webClientId); _googleInitialized = true; } /// Google bejelentkezés → Supabase session. /// Visszatérés: true = bejelentkezve; false = a felhasználó megszakította. /// Egyéb hibánál [AuthServiceException]-t dob, magyar üzenettel. Future signInWithGoogle() async { if (isBusy.value) return false; isBusy.value = true; try { await _ensureGoogleInitialized(); // Interaktív bejelentkezés — megszakítást kivétel jelzi (7.x). final GoogleSignInAccount account; try { account = await GoogleSignIn.instance.authenticate(); } on GoogleSignInException catch (e) { if (e.code == GoogleSignInExceptionCode.canceled) return false; throw AuthServiceException('Google-bejelentkezési hiba: ' '${e.description ?? e.code.name}'); } final idToken = account.authentication.idToken; if (idToken == null) { throw AuthServiceException( 'A Google nem adott vissza idToken-t — ellenőrizd a ' 'GOOGLE_WEB_CLIENT_ID beállítást.'); } // accessToken a 7.x-ben külön engedélyezési lépés (a Supabase // Google idToken-flow-ja kéri). const scopes = ['email', 'profile']; final authorization = await account.authorizationClient.authorizationForScopes(scopes) ?? await account.authorizationClient.authorizeScopes(scopes); await _supabase.auth.signInWithIdToken( provider: OAuthProvider.google, idToken: idToken, accessToken: authorization.accessToken, ); // currentUser-t az onAuthStateChange listener állítja be. if (kDebugMode) { debugPrint('[Auth] Bejelentkezve: ${account.email}'); } return true; } on AuthException catch (e) { throw AuthServiceException('Supabase hitelesítési hiba: ${e.message}'); } finally { isBusy.value = false; } } /// Kijelentkezés mindkét oldalról (Supabase session + Google fiók). Future signOut() async { isBusy.value = true; try { await _supabase.auth.signOut(); if (_googleInitialized) { try { await GoogleSignIn.instance.signOut(); } catch (_) { // A Google-oldali kijelentkezés hibája nem kritikus. } } } finally { isBusy.value = false; } } }