import ts from 'typescript/lib/tsserverlibrary';
import { SchemaLoaderResult } from '@gql.tada/internal';
/*!@ts-ignore*/
import { FragmentDefinitionNode } from 'graphql';

declare function init(modules: { typescript: typeof ts }): void;

/** Mutable record of configuration and loading failures.
 *
 * These are surfaced as editor diagnostics on files containing GraphQL
 * documents, so a misconfigured plugin doesn't fail silently with its
 * errors only visible in the tsserver log. */
interface SchemaErrors {
  /** The plugin configuration itself is invalid, e.g. the "schema" option is missing. */
  config: string | null;
  /** Schemas that failed to (re)load, e.g. a missing file, invalid SDL, or an
   * unreachable URL; keyed by schema name (`null` for single-schema setups
   * and failures that can't be attributed to a single schema). */
  load: Map<string | null, string>;
  /** Typings (tada output) files that failed to be written, keyed by their resolved output path. */
  write: Map<string, string>;
}
interface SchemaRef {
  current: SchemaLoaderResult | null;
  multi: {
    [name: string]: SchemaLoaderResult | null;
  };
  version: number;
  readonly errors: SchemaErrors;
  /** Typings output paths successfully written this session, mapped to their last write time. */
  readonly outputLocations: ReadonlyMap<string, number>;
  /** File-based schema origins, keyed by schema name (`null` for single-schema setups). */
  readonly sourceLocations: ReadonlyMap<string | null, string>;
  /** gql.tada turbo cache files, keyed by schema name (`null` for single-schema setups). */
  readonly turboLocations: ReadonlyMap<string | null, string>;
  /** Best-effort detection of schema file changes that the file watcher
   * missed; throttled internally, so it's safe to call often. */
  checkStale(): void;
}

declare function getGraphQLDiagnostics(
  filename: string,
  schema: SchemaRef,
  info: ts.server.PluginCreateInfo
): ts.Diagnostic[] | undefined;

declare function unrollTadaFragments(
  fragmentsArray: ts.ArrayLiteralExpression,
  wip: FragmentDefinitionNode[],
  info: ts.server.PluginCreateInfo
): FragmentDefinitionNode[];
type FindAllCallExpressionsOptions = {
  /** Search for externally defined fragment documents.
   * @defaultValue `true` */
  searchExternal?: boolean;
  /** Collect and unroll fragment definitions into the `fragments` result.
   * @defaultValue `true` */
  collectFragments?: boolean;
};
declare function findAllCallExpressions(
  sourceFile: ts.SourceFile,
  info: ts.server.PluginCreateInfo,
  options?: boolean | FindAllCallExpressionsOptions
): {
  nodes: Array<{
    node: ts.StringLiteralLike;
    schema: string | null;
    tadaFragmentRefs?: readonly ts.Identifier[] | null;
  }>;
  fragments: Array<FragmentDefinitionNode>;
};
declare function findAllPersistedCallExpressions(
  sourceFile: ts.SourceFile
): Array<ts.CallExpression>;
declare function findAllPersistedCallExpressions(
  sourceFile: ts.SourceFile,
  info: ts.server.PluginCreateInfo
): Array<{
  node: ts.CallExpression;
  schema: string | null;
}>;

declare const getDocumentReferenceFromTypeQuery: (
  typeQuery: ts.TypeQueryNode,
  filename: string,
  info: ts.server.PluginCreateInfo
) => {
  node: ts.CallExpression | null;
  filename: string;
};
declare const getDocumentReferenceFromDocumentNode: (
  documentNodeArgument: ts.Identifier | ts.CallExpression,
  filename: string,
  info: ts.server.PluginCreateInfo
) => {
  node: ts.CallExpression | null;
  filename: string;
};

export {
  type FindAllCallExpressionsOptions,
  findAllCallExpressions,
  findAllPersistedCallExpressions,
  getDocumentReferenceFromDocumentNode,
  getDocumentReferenceFromTypeQuery,
  getGraphQLDiagnostics,
  init,
  unrollTadaFragments,
};
