import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_login_yandex/flutter_login_yandex.dart'; import 'package:eatvio_app/core/app_router.dart'; import 'package:vk_id/vk_id.dart'; import 'package:webview_flutter/webview_flutter.dart'; class VkAuthResult { VkAuthResult({required this.accessToken, this.refreshToken, this.userId, this.firstName, this.lastName, this.email, this.phone, this.gender, this.birthDate}); final String accessToken; final String? refreshToken; final String? userId; final String? firstName; final String? lastName; final String? email; final String? phone; final String? gender; final String? birthDate; } class SocialAuthFacade { static Future signInWithVk({required BuildContext context}) async { final result = await signInWithVkAndFetchProfile(context: context); return result?.accessToken; } static Future signInWithVkAndFetchProfile({required BuildContext context}) async { final clientIdStr = dotenv.maybeGet('VK_CLIENT_ID')?.trim() ?? Platform.environment['VK_CLIENT_ID']; if (clientIdStr == null || clientIdStr.isEmpty) { return null; } try { dynamic controller = VkIDController(clID: int.parse(clientIdStr)); final authUri = controller.generateAuthorizeLinkWithCodeVerifier(); final redirectScheme = 'vk$clientIdStr://'; final redirectParams = await _presentOAuthWebView(context: context, initialUrl: authUri.toString(), redirectSchemePrefix: redirectScheme); if (redirectParams == null) return null; final code = redirectParams['code']; final deviceId = redirectParams['device_id']; if (code == null || deviceId == null) return null; final tokenResponse = await controller.exchangeAuthorizationCodeForToken(code: code, deviceId: deviceId); final accessToken = _extractAccessToken(tokenResponse); if (accessToken == null) return null; return VkAuthResult(accessToken: accessToken); } catch (_) { return null; } } static Future signInWithOk() async { final context = AppRouter.navigatorKey.currentContext; if (context == null) return null; return _signInWithVkIdProvider(context: context, provider: 'ok'); } static Future signInWithMailRu() async { final context = AppRouter.navigatorKey.currentContext; if (context == null) return null; return _signInWithVkIdProvider(context: context, provider: 'mail'); } static Future signInWithYandex() async { final clientId = dotenv.maybeGet('YANDEX_CLIENT_ID')?.trim() ?? Platform.environment['YANDEX_CLIENT_ID']; final redirectUri = dotenv.maybeGet('YANDEX_REDIRECT_URI')?.trim() ?? Platform.environment['YANDEX_REDIRECT_URI']; if (clientId == null || clientId.isEmpty || redirectUri == null || redirectUri.isEmpty) { return null; } try { final plugin = FlutterLoginYandex(); final response = await plugin.signIn(); final token = (response is Map) ? response['token'] as String? : null; return (token != null && token.isNotEmpty) ? token : null; } catch (_) { return null; } } static Future _signInWithVkIdProvider({required BuildContext context, required String provider}) async { final clientIdStr = dotenv.maybeGet('VK_CLIENT_ID')?.trim() ?? Platform.environment['VK_CLIENT_ID']; if (clientIdStr == null || clientIdStr.isEmpty) { return null; } try { dynamic controller = VkIDController(clID: int.parse(clientIdStr)); final authUri = controller.generateAuthorizeLinkWithCodeVerifier(provider: provider); final redirectScheme = 'vk$clientIdStr://'; final redirectParams = await _presentOAuthWebView(context: context, initialUrl: authUri.toString(), redirectSchemePrefix: redirectScheme); if (redirectParams == null) return null; final code = redirectParams['code']; final deviceId = redirectParams['device_id']; if (code == null || deviceId == null) return null; final tokenResponse = await controller.exchangeAuthorizationCodeForToken(code: code, deviceId: deviceId, provider: provider); final accessToken = _extractAccessToken(tokenResponse); return accessToken; } catch (_) { return null; } } static String? _extractAccessToken(dynamic tokenResponse) { if (tokenResponse == null) return null; if (tokenResponse is Map) { return (tokenResponse['access_token'] as String?) ?? (tokenResponse['token'] as String?); } try { final token = (tokenResponse as dynamic).accessToken as String?; if (token != null && token.isNotEmpty) return token; } catch (_) {} try { final token = (tokenResponse as dynamic).token as String?; if (token != null && token.isNotEmpty) return token; } catch (_) {} return null; } static Future?> _presentOAuthWebView({ required BuildContext context, required String initialUrl, required String redirectSchemePrefix, }) async { final controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setNavigationDelegate( NavigationDelegate( onNavigationRequest: (request) { final url = request.url; if (url.startsWith(redirectSchemePrefix)) { final uri = Uri.parse(url); final params = {}..addAll(uri.queryParameters); Navigator.of(context, rootNavigator: true).pop(params); return NavigationDecision.prevent; } return NavigationDecision.navigate; }, ), ) ..loadRequest(Uri.parse(initialUrl)); return showDialog>( context: context, barrierDismissible: false, builder: (_) { return Dialog( insetPadding: const EdgeInsets.all(16), child: SizedBox(height: 560, child: WebViewWidget(controller: controller)), ); }, ); } }