import 'package:kasy_kit/core/data/api/base_api_exceptions.dart';
import 'package:kasy_kit/core/data/api/http_client.dart';
import 'package:kasy_kit/core/data/entities/user_entity.dart';
import 'package:kasy_kit/features/authentication/api/authentication_api_interface.dart';
import 'package:kasy_kit/features/authentication/repositories/exceptions/authentication_exceptions.dart';
import 'package:flutter/services.dart' show PlatformException;
import 'package:dio/dio.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:logger/logger.dart';
import 'package:sign_in_with_apple/sign_in_with_apple.dart';


final authenticationApiProvider = Provider<AuthenticationApi>(
  (ref) => HttpAuthenticationApi(
    logger: Logger(),
    client: ref.read(httpClientProvider),
  ),
);

class HttpAuthenticationApi implements AuthenticationApi {
  final Logger _logger;
  final HttpClient _client;

  HttpAuthenticationApi({
    required Logger logger,
    required HttpClient client,
  })  : _logger = logger,
        _client = client;

  @override
  Future<void> init() async {
  }

  @override
  Future<Credentials> signup(String email, String password) async {
    try {
      final response = await _client.post(
        '/auth/signup',
        data: {
          'email': email,
          'password': password,
        },
      );
      return Credentials.fromJson(response.data as Map<String, dynamic>);
    } on DioException catch (e, stackTrace) {
      _logger.e(e, stackTrace: stackTrace);
      throw ApiError.fromDioException(e);
    } catch (e) {
      _logger.e(e);
      throw ApiError(
        code: 0,
        message: '$e',
      );
    }
  }

  @override
  Future<Credentials> signin(String email, String password) async {
    try {
      final response = await _client.post(
        '/auth/signin',
        data: {
          'email': email,
          'password': password,
        },
      );
      return Credentials.fromJson(response.data as Map<String, dynamic>);
    } on DioException catch (e) {
      _logger.e(e);
      throw ApiError.fromDioException(e);
    } catch (e) {
      _logger.e(e);
      throw ApiError(
        code: 0,
        message: '$e',
      );
    }
  }

  @override
  Future<void> recoverPassword(String email) async {
    try {
      await _client.post(
        '/auth/recover-password',
        data: {
          'email': email,
        },
      );
    } on DioException catch (e) {
      _logger.e(e);
      throw ApiError.fromDioException(e);
    } catch (e) {
      _logger.e(e);
      throw ApiError(
        code: 0,
        message: '$e',
      );
    }
  }

  @override
  Future<Credentials> signinAnonymously() async {
    // REST API backends typically do not support anonymous accounts natively.
    // Option A – skip anonymous sign-in: remove anonymous auth from the
    //   onboarding flow and require full registration before using the app.
    // Option B – create a guest session on your backend:
    //   final response = await _client.post('/auth/guest');
    //   return Credentials.fromJson(response.data as Map<String, dynamic>);
    throw UnimplementedError(
      '❌ Implement signinAnonymously() in authentication_api.dart.\n'
      'See the comment above for the two recommended approaches.',
    );
  }

  @override
  Future<void> signout() async {}

  @override
  Future<Credentials> signinWithGoogle() async {
    final googleSignIn = GoogleSignIn.instance;
    await googleSignIn.initialize(
      clientId: const String.fromEnvironment('GOOGLE_CLIENT_ID'),
    );
    late final GoogleSignInAccount googleUser;
    try {
      googleUser = await googleSignIn.authenticate();
    } on GoogleSignInException catch (e) {
      if (e.code == GoogleSignInExceptionCode.canceled) throw const UserCancelledSignInException();
      rethrow;
    } on PlatformException catch (e) {
      if (e.code == 'sign_in_canceled' || e.code == 'sign_in_cancelled') {
        throw const UserCancelledSignInException();
      }
      rethrow;
    }
    final googleAuth = await googleUser.authentication;
    throw UnimplementedError('''
    ❌ You must edit lib/features/authentication/api/authentication_api.dart
    to send the Oauth2 token result to your backend.
    Available tokens:
      googleAuth.idToken: ${googleAuth.idToken}
    ''');
  }

  @override
  Future<Credentials> signinWithGooglePlay() async {
    // google_sign_in 7.x removed SignInOption.games.
    // For Play Games support, use the games_services package separately.
    return signinWithGoogle();
  }

  @override
  Future<Credentials> signinWithApple() async {
    late final AuthorizationCredentialAppleID credential;
    try {
      credential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
      );
    } on SignInWithAppleAuthorizationException catch (e) {
      if (e.code == AuthorizationErrorCode.canceled) throw const UserCancelledSignInException();
      rethrow;
    }
    throw UnimplementedError('''
    ❌ You must edit lib/features/authentication/api/authentication_api.dart 
    to send the Oauth2 token result to your backend
    ----------------
    Please follow the instructions here:
    https://pub.dev/packages/sign_in_with_apple
    ''');
    
    
  }

  @override
  Future<Credentials> signinWithFacebook() async {
    final LoginResult loginResult = await FacebookAuth.instance.login(
      permissions: ['email', 'public_profile'],
    );
    if (loginResult.status == LoginStatus.cancelled) throw const UserCancelledSignInException();
    final token = loginResult.accessToken?.tokenString;
    throw UnimplementedError('''
    ❌ You must edit lib/features/authentication/api/authentication_api.dart
    to send the Oauth2 token result to your backend.
    Available token: $token
    Follow: https://facebook.meedu.app/docs/5.x.x/intro
    ''');
  }

  @override
  Future<Credentials?> get() {
    // don't implement this method for REST api mode
    // This is only for Firebase or Supabase mode
    throw UnimplementedError();
  }

  @override
  Future<String?> getCurrentUserEmail() async => null;

  @override
  Future<String?> getCurrentUserDisplayName() async => null;

  /// Links an anonymous/guest session to a permanent Google account.
  ///
  /// Expected flow:
  ///   1. Collect the Google OAuth token (already done below via signinWithGoogle).
  ///   2. Send it to your backend alongside the current guest token so the
  ///      backend can merge the accounts:
  ///        POST /auth/link-google  {id_token, access_token}  → Credentials
  @override
  Future<Credentials> signupFromAnonymousWithGoogle() async {
    final googleSignIn = GoogleSignIn.instance;
    await googleSignIn.initialize(
      clientId: const String.fromEnvironment('GOOGLE_CLIENT_ID'),
    );
    late final GoogleSignInAccount googleUser;
    try {
      googleUser = await googleSignIn.authenticate();
    } on GoogleSignInException catch (e) {
      if (e.code == GoogleSignInExceptionCode.canceled) throw const UserCancelledSignInException();
      rethrow;
    } on PlatformException catch (e) {
      if (e.code == 'sign_in_canceled' || e.code == 'sign_in_cancelled') {
        throw const UserCancelledSignInException();
      }
      rethrow;
    }
    final googleAuth = await googleUser.authentication;
    throw UnimplementedError(
      '❌ Send the tokens to your backend to merge the guest account.\n'
      '   idToken: ${googleAuth.idToken}\n'
      '   Example: POST /auth/link-google {id_token}',
    );
  }

  /// Links an anonymous/guest session to a permanent Apple account.
  ///
  /// Expected flow:
  ///   POST /auth/link-apple  {identity_token, authorization_code}  → Credentials
  @override
  Future<Credentials> signupFromAnonymousWithApple() async {
    late final AuthorizationCredentialAppleID credential;
    try {
      credential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
      );
    } on SignInWithAppleAuthorizationException catch (e) {
      if (e.code == AuthorizationErrorCode.canceled) throw const UserCancelledSignInException();
      rethrow;
    }
    throw UnimplementedError(
      '❌ Send the tokens to your backend to merge the guest account.\n'
      '   identityToken:      ${credential.identityToken}\n'
      '   authorizationCode:  ${credential.authorizationCode}\n'
      '   Example: POST /auth/link-apple {identity_token, authorization_code}',
    );
  }

  /// Links an anonymous/guest session to a permanent Facebook account.
  ///
  /// Expected flow:
  ///   POST /auth/link-facebook  {access_token}  → Credentials
  @override
  Future<Credentials> signupFromAnonymousWithFacebook() async {
    final loginResult = await FacebookAuth.instance.login(
      permissions: ['email', 'public_profile'],
    );
    if (loginResult.status == LoginStatus.cancelled) throw const UserCancelledSignInException();
    final token = loginResult.accessToken?.tokenString;
    throw UnimplementedError(
      '❌ Send the token to your backend to merge the guest account.\n'
      '   accessToken: $token\n'
      '   Example: POST /auth/link-facebook {access_token}',
    );
  }

  @override
  Future<String> signinWithPhone(String phoneNumber) {
    throw UnimplementedError();
  }

  @override
  Future<Credentials> verifyPhoneAuth(String verificationId, String otp) {
    throw UnimplementedError();
  }

  @override
  Future<String> updateAuthPhone(String phoneNumber) {
    throw UnimplementedError();
  }

  @override
  Future<Credentials> confirmLinkPhoneAuth(String verificationId, String otp) {
    throw UnimplementedError();
  }
}
