import 'dart:convert';

import 'package:auth/src/core/data/models/sign_up_request_model.dart';
import 'package:auth/src/core/data/models/sign_up_response_model.dart';
import 'package:auth/src/core/data/models/two_fa_secret_response_model.dart';
import 'package:auth/src/features/sign_up/domain/entities/sign_up_request_entity.dart';
import 'package:auth/src/features/sign_up/domain/entities/two_fa_secret_entity.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:sf_infrastructure/sf_infrastructure.dart';

import 'auth_remote_datasource.dart';

class AuthRemoteDatasourceImpl implements AuthRemoteDatasource {
  AuthRemoteDatasourceImpl(this._repository);

  final QuestiaRepository _repository;

  @override
  Future<void> requestPhoneCode({required String phone}) async {
    try {
      await _repository.post<void>(
        '/auth/link-phone/request-code',
        body: <String, dynamic>{'phone': phone},
      );
    } on DioException catch (error) {
      throw _mapDioError(
        error,
        defaultMessage: error.response?.data ?? 'Error to request phone code',
      );
    }
  }

  @override
  Future<void> verifyPhoneCode({
    required String phone,
    required String code,
  }) async {
    try {
      await _repository.post<void>(
        '/auth/link-phone/verify-code',
        body: <String, dynamic>{'phone': phone, 'code': code},
      );
    } on DioException catch (error) {
      throw _mapDioError(error, defaultMessage: 'Error in verification code');
    }
  }

  @override
  Future<String> login({
    required String email,
    required String password,
  }) async {
    try {
      final response = await _repository.post<Map<String, dynamic>>(
        '/auth/login',
        body: <String, dynamic>{'email': email, 'password': password},
      );
      final token = response.data!['token'];
      return token;
    } on DioException catch (error) {
      throw _mapDioError(
        error,
        defaultMessage: error.message ?? 'Error in login',
      );
    }
  }

  @override
  Future<String> twoFALogin({
    required String token,
    required String code,
  }) async {
    try {
      final response = await _repository.post<String>(
        '/auth/totp/login',
        body: <String, dynamic>{
          'token': token,
          'code': code,
          'rememberMe': true,
        },
      );

      final data = response.data;
      if (data == null || data.isEmpty) {
        throw Exception('Empty response from /auth/totp/login');
      }

      return data;
    } on DioException catch (error) {
      throw _mapDioError(error, defaultMessage: 'Error in twoFALogin');
    }
  }

  @override
  Future<String> signUp({required SignUpRequestEntity request}) async {
    try {
      final body = request.toModel().toJson();
      debugPrint(body.toString());
      debugPrint(const JsonEncoder.withIndent('  ').convert(body));

      final response = await _repository.post<Map<String, dynamic>>(
        '/payment-profiles/signup',
        body: body,
      );

      final data = response.data;
      if (data == null || data.isEmpty) {
        throw Exception('Empty response from /payment-profiles/signup');
      }

      final parsed = SignUpResponseModel.fromJson(data);

      if (!parsed.isCreated) {
        throw Exception('Sign up failed: isCreated=false');
      }

      final token = parsed.item.token.trim();
      if (token.isEmpty) {
        throw Exception('Sign up response has empty token');
      }

      return token;
    } on DioException catch (error) {
      throw _mapDioError(error, defaultMessage: 'Error in signUp');
    }
  }

  @override
  Future<TwoFASecretEntity> generateTwoFASignUp({required String token}) async {
    try {
      final response = await _repository.post<Map<String, dynamic>>(
        '/auth/totp/secret',
        body: <String, dynamic>{'token': token},
      );

      final data = response.data;
      if (data == null || data.isEmpty) {
        throw Exception('Empty response from /auth/totp/secret');
      }

      final model = TwoFASecretResponseModel.fromJson(data);
      return model.toEntity();
    } on DioException catch (error) {
      throw _mapDioError(error, defaultMessage: 'Error in twoFASignUp');
    }
  }

  @override
  Future<String> verifyTwoFACodeSignUp({
    required String token,
    required String code,
  }) async {
    try {
      final response = await _repository.post<String>(
        '/auth/totp/code',
        body: <String, dynamic>{'token': token, 'code': code},
      );

      final data = response.data;
      if (data == null || data.isEmpty) {
        throw Exception('Empty response from /auth/totp/code');
      }

      return data;
    } on DioException catch (error) {
      throw _mapDioError(error, defaultMessage: 'Error in twoFaCodeSignUp');
    }
  }
}

Exception _mapDioError(DioException error, {required String defaultMessage}) {
  final apiMsg = _extractApiMessage(error.response?.data);
  final msg = apiMsg ?? error.message ?? defaultMessage;
  return Exception(msg);
}

String? _extractApiMessage(Object? data) {
  if (data == null) return null;

  if (data is Map) {
    final errorObj = data['error'];
    if (errorObj is Map && errorObj['message'] is String) {
      return (errorObj['message'] as String).trim();
    }
    if (data['message'] is String) {
      return (data['message'] as String).trim();
    }
    return null;
  }

  if (data is String) {
    final raw = data.trim();
    if (raw.isEmpty) return null;

    try {
      final decoded = jsonDecode(raw);
      return _extractApiMessage(decoded);
    } catch (_) {
      return raw;
    }
  }

  return null;
}
