import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:injectable/injectable.dart';
import 'package:krow/core/application/di/injectable.dart';
import 'package:path_provider/path_provider.dart';

class GraphQLConfig {
  static HttpLink httpLink = HttpLink(
    dotenv.env['BASE_URL']!,
    defaultHeaders: {
      'Content-Type': 'application/json',
    },
  );
  static AuthLink authLink = AuthLink(
    getToken: () async {
      User? user = FirebaseAuth.instance.currentUser;
      if (user != null) {
        return 'Bearer ${await user.getIdToken()}';
      }
      return null;
    },
  );

  static Link link = authLink.concat(httpLink);

  Future<GraphQLClient> configClient() async {
    var path = await getApplicationDocumentsDirectory();
    Store? store;
    if (currentEnv != 'background') {
      store = await HiveStore.open(path: '${path.path}/gql_cache');
    }

    return GraphQLClient(
        link: link,
        cache: GraphQLCache(
          store: store,
        ),
        defaultPolicies: DefaultPolicies(
          mutate: Policies(
            cacheReread: CacheRereadPolicy.ignoreOptimisitic,
            error: ErrorPolicy.all,
            fetch: FetchPolicy.networkOnly,
          ),
          query: Policies(
            cacheReread: CacheRereadPolicy.ignoreOptimisitic,
            error: ErrorPolicy.all,
            fetch: FetchPolicy.networkOnly,
          ),
        ));
  }
}

@Singleton()
class ApiClient {
  static final GraphQLConfig _graphQLConfig = GraphQLConfig();
  final Future<GraphQLClient> _client = _graphQLConfig.configClient();

  Future<QueryResult> query(
      {required String schema, Map<String, dynamic>? body}) async {
    final QueryOptions options = QueryOptions(
      document: gql(schema),
      variables: body ?? {},
    );
    return (await _client).query(options);
  }

  Stream<QueryResult?> queryWithCache({
    required String schema,
    Map<String, dynamic>? body,
  }) async* {
    final WatchQueryOptions options = WatchQueryOptions(
        document: gql(schema),
        variables: body ?? {},
        fetchPolicy: FetchPolicy.cacheAndNetwork);

    var result = (await _client).watchQuery(options).fetchResults();
    yield result.eagerResult;
    yield await result.networkResult;
  }

  Future<QueryResult> mutate(
      {required String schema, Map<String, dynamic>? body}) async {
    final MutationOptions options = MutationOptions(
      document: gql(schema),
      variables: body ?? {},
    );
    return (await _client).mutate(options);
  }

  void dropCache() async {
    (await _client).cache.store.reset();
  }
}


