import '@angular/compiler';
import { Injector, runInInjectionContext } from '@angular/core';
import { Apollo } from 'apollo-angular';
import { gql } from 'graphql-tag';
import { of } from 'rxjs';
import { queryFind } from './query-find';

const MOCK_QUERY = gql`
  query FindTag($query: QueryStatement, $constraint: QueryStatement) {
    object: iamFindTag(query: $query, constraint: $constraint) {
      id
      name
    }
  }
`;

interface Tag {
  id: string;
  name: string;
}

describe('queryFind', () => {
  let apolloQuerySpy: ReturnType<typeof vi.fn>;
  let injector: Injector;

  beforeEach(() => {
    apolloQuerySpy = vi.fn().mockReturnValue(of({ data: { object: { id: '1', name: 'Tag A' } } }));

    injector = Injector.create({
      providers: [{ provide: Apollo, useValue: { query: apolloQuerySpy } }],
    });
  });

  function run(fields?: string, variables?: Record<string, unknown>) {
    return runInInjectionContext(injector, () =>
      queryFind<Tag>(MOCK_QUERY, 'object', fields, variables as never),
    );
  }

  it('emits the single record under the given key', () => {
    let result: Tag | null = null;
    run().subscribe((r) => (result = r));
    expect(result).toEqual({ id: '1', name: 'Tag A' });
  });

  it('emits null when the key is missing', () => {
    apolloQuerySpy.mockReturnValue(of({ data: {} }));
    let result: Tag | null = { id: 'x', name: 'x' };
    run().subscribe((r) => (result = r));
    expect(result).toBeNull();
  });

  it('forwards query + constraint variables to apollo.query', () => {
    run(undefined, { query: { where: { name: 'A' } } }).subscribe();
    const arg = apolloQuerySpy.mock.calls[0][0];
    expect(arg.variables).toEqual({ query: { where: { name: 'A' } } });
  });

  it('passes headers into the context', () => {
    run(undefined, { headers: { 'X-Tenant-Id': 'abc' } }).subscribe();
    const arg = apolloQuerySpy.mock.calls[0][0];
    expect(arg.context).toEqual({ headers: { 'X-Tenant-Id': 'abc' } });
  });
});
