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

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

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

describe('queryFindById', () => {
  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(id: string, fields?: string, variables?: Record<string, unknown>) {
    return runInInjectionContext(injector, () =>
      queryFindById<Tag>(MOCK_QUERY, 'object', id, fields, variables as never),
    );
  }

  it('passes the id into variables', () => {
    run('42').subscribe();
    const arg = apolloQuerySpy.mock.calls[0][0];
    expect(arg.variables).toMatchObject({ id: '42' });
  });

  it('emits the record under the given key', () => {
    let result: Tag | null = null;
    run('1').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('1').subscribe((r) => (result = r));
    expect(result).toBeNull();
  });

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