import 'dart:async'; import 'dart:convert'; import 'package:http/http.dart' as http; import '../../../core/network/api_error.dart'; import '../domain/auth_models.dart'; class AuthApiClient { const AuthApiClient({ required this.httpClient, required this.baseUri, this.timeout = const Duration(seconds: 10), }); final http.Client httpClient; final Uri baseUri; final Duration timeout; Future phoneLogin(PhoneLoginRequest request) async { final response = await httpClient .post( _resolve('/api/v1/tdc114plus/auth/phone-login'), headers: const { 'accept': 'application/json', 'content-type': 'application/json', }, body: jsonEncode(request.toJson()), ) .timeout(timeout); final decoded = _decodeObject(response.body); if (response.statusCode < 200 || response.statusCode >= 300) { throw ApiException( statusCode: response.statusCode, apiError: ApiError.fromJson(decoded), ); } return PhoneLoginResponse.fromJson(decoded); } Future requestPhoneLoginLink( PhoneLoginLinkInitRequest request, ) async { final response = await httpClient .post( _resolve('/api/v1/auth/link/init'), headers: const { 'accept': 'application/json', 'content-type': 'application/json', }, body: jsonEncode(request.toJson()), ) .timeout(timeout); final decoded = _decodeObject(response.body); if (response.statusCode < 200 || response.statusCode >= 300) { throw ApiException( statusCode: response.statusCode, apiError: ApiError.fromJson(decoded), ); } return PhoneLoginLinkInitResponse.fromJson(decoded); } Future pollPhoneLoginLink( PhoneLoginLinkPollRequest request, ) async { final response = await httpClient .post( _resolve('/api/v1/auth/link/poll'), headers: const { 'accept': 'application/json', 'content-type': 'application/json', }, body: jsonEncode(request.toJson()), ) .timeout(timeout); final decoded = _decodeObject(response.body); if (response.statusCode < 200 || response.statusCode >= 300) { throw ApiException( statusCode: response.statusCode, apiError: ApiError.fromJson(decoded), ); } return PhoneLoginLinkPollResponse.fromJson(decoded); } Uri _resolve(String path) { final normalizedBase = baseUri.path.endsWith('/') ? baseUri : baseUri.replace(path: '${baseUri.path}/'); return normalizedBase.resolve(path.replaceFirst(RegExp(r'^/'), '')); } Map _decodeObject(String body) { final decoded = jsonDecode(body); if (decoded is Map) { return decoded; } throw const FormatException('Expected JSON object response'); } }