import '@angular/compiler';
import { Injector, runInInjectionContext } from '@angular/core';
import { Apollo } from 'apollo-angular';
import { gql } from 'graphql-tag';
import { of } from 'rxjs';
import { mutateUpdate } from './mutate-update';

const MOCK_MUTATION = gql`
  mutation UpdateTag($payload: UpdateTagInput!) {
    iamUpdateTagById(payload: $payload) {
      id
    }
  }
`;

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

  beforeEach(() => {
    apolloMutateSpy = vi.fn().mockReturnValue(of({ data: { iamUpdateTagById: { id: '1' } } }));
    injector = Injector.create({
      providers: [{ provide: Apollo, useValue: { mutate: apolloMutateSpy } }],
    });
  });

  function run(payload: Record<string, unknown>, headers?: Record<string, string>) {
    return runInInjectionContext(injector, () => mutateUpdate(MOCK_MUTATION, payload, headers));
  }

  it('calls apollo.mutate with the payload wrapped under `payload`', () => {
    run({ id: '1', name: 'Updated' }).subscribe();
    expect(apolloMutateSpy).toHaveBeenCalledWith({
      mutation: MOCK_MUTATION,
      variables: { payload: { id: '1', name: 'Updated' } },
      context: { headers: undefined },
    });
  });

  it('forwards custom headers to the mutation context', () => {
    run({ id: '1', name: 'Updated' }, { 'X-Tenant-Id': 'abc' }).subscribe();
    const arg = apolloMutateSpy.mock.calls[0][0];
    expect(arg.context).toEqual({ headers: { 'X-Tenant-Id': 'abc' } });
  });

  it('returns the apollo mutation observable', () => {
    let emitted: unknown;
    run({ id: '1', name: 'Updated' }).subscribe((r) => (emitted = r));
    expect(emitted).toEqual({ data: { iamUpdateTagById: { id: '1' } } });
  });
});
