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<PhoneLoginResponse> 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<PhoneLoginLinkInitResponse> 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<PhoneLoginLinkPollResponse> 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<String, dynamic> _decodeObject(String body) {
    final decoded = jsonDecode(body);
    if (decoded is Map<String, dynamic>) {
      return decoded;
    }
    throw const FormatException('Expected JSON object response');
  }
}
