import 'dart:async';
import 'package:alt_client/src/contracts/alt_api_result.dart';
import 'package:alt_client/src/integrations/socket/alt_socket_client.dart';
import 'package:alt_client/src/generated/alt/v1/market.pb.dart';

/// Repository responsible for handling market-related data operations.
///
/// Wraps [AltSocketClient] calls for listing instruments and historical bars,
/// transforming raw socket responses or failures into structured [AltApiResult]s.
class MarketRepository {
  final AltSocketClient _client;

  MarketRepository(this._client);

  /// Lists market instruments matching the given [request].
  Future<AltApiResult<ListInstrumentsResponse>> listInstruments(
    ListInstrumentsRequest request, {
    Duration timeout = const Duration(seconds: 2),
  }) async {
    if (!_client.isAlive) {
      return const AltApiResult.transportFailure(
        AltTransportKind.disconnected,
        detail: 'client is not alive',
      );
    }
    try {
      final response = await _client.listInstruments(request, timeout: timeout);
      final errorInfo = altResponseError(response);
      if (errorInfo != null) {
        return AltApiResult.apiError(AltApiError.fromErrorInfo(errorInfo));
      }
      return AltApiResult.success(response);
    } on TimeoutException catch (e) {
      return AltApiResult.transportFailure(
        AltTransportKind.timeout,
        detail: e.toString(),
      );
    } on StateError catch (e) {
      return AltApiResult.transportFailure(
        AltTransportKind.decodeFailure,
        detail: e.toString(),
      );
    } catch (e) {
      final errStr = e.toString().toLowerCase();
      if (errStr.contains('disconnect') ||
          errStr.contains('closed') ||
          errStr.contains('not connected')) {
        return AltApiResult.transportFailure(
          AltTransportKind.disconnected,
          detail: e.toString(),
        );
      }
      return AltApiResult.transportFailure(
        AltTransportKind.unknown,
        detail: e.toString(),
      );
    }
  }

  /// Lists bar (historical) data matching the given [request].
  Future<AltApiResult<ListBarsResponse>> listBars(
    ListBarsRequest request, {
    Duration timeout = const Duration(seconds: 2),
  }) async {
    if (!_client.isAlive) {
      return const AltApiResult.transportFailure(
        AltTransportKind.disconnected,
        detail: 'client is not alive',
      );
    }
    try {
      final response = await _client.listBars(request, timeout: timeout);
      final errorInfo = altResponseError(response);
      if (errorInfo != null) {
        return AltApiResult.apiError(AltApiError.fromErrorInfo(errorInfo));
      }
      return AltApiResult.success(response);
    } on TimeoutException catch (e) {
      return AltApiResult.transportFailure(
        AltTransportKind.timeout,
        detail: e.toString(),
      );
    } on StateError catch (e) {
      return AltApiResult.transportFailure(
        AltTransportKind.decodeFailure,
        detail: e.toString(),
      );
    } catch (e) {
      final errStr = e.toString().toLowerCase();
      if (errStr.contains('disconnect') ||
          errStr.contains('closed') ||
          errStr.contains('not connected')) {
        return AltApiResult.transportFailure(
          AltTransportKind.disconnected,
          detail: e.toString(),
        );
      }
      return AltApiResult.transportFailure(
        AltTransportKind.unknown,
        detail: e.toString(),
      );
    }
  }
}
