import { provideHttpClient } from '@angular/common/http';
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
import { TestBed } from '@angular/core/testing';
import { SocialIdentityApiGateway } from './social-identity-api.gateway';
import { SocialProvider } from './social-identity-gateway.interface';

/**
 * FH-4.1/FH-4.2. The whole point of this surface is what it does NOT carry:
 * no client secret, no access token, no PKCE code verifier. These tests pin
 * that shape, because a future "just add completeCallback back" would look
 * harmless in review and would move verifier custody into the browser.
 */
describe('SocialIdentityApiGateway', () => {
  let gateway: SocialIdentityApiGateway;
  let httpTesting: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [SocialIdentityApiGateway, provideHttpClient(), provideHttpClientTesting()],
    });
    gateway = TestBed.inject(SocialIdentityApiGateway);
    httpTesting = TestBed.inject(HttpTestingController);
  });

  afterEach(() => httpTesting.verify());

  const providers: SocialProvider[] = ['vk', 'yandex'];

  for (const provider of providers) {
    it(`asks the backend for the ${provider} authorize URL and sends no secret material`, () => {
      let resolved: string | undefined;
      gateway.getAuthorizeUrl(provider).subscribe(url => (resolved = url));

      const request = httpTesting.expectOne(`/api/identity/v1/${provider}/authorize`);
      expect(request.request.method).toBe('GET');
      expect(request.request.body).toBeNull();
      expect(request.request.urlWithParams).not.toContain('code_verifier');
      expect(request.request.urlWithParams).not.toContain('client_secret');

      request.flush({ url: `https://id.example.test/${provider}/authorize?state=abc` });
      expect(resolved).toContain(provider);
    });
  }

  it('passes returnTo through as a query parameter', () => {
    gateway.getAuthorizeUrl('vk', '/cart').subscribe();

    const request = httpTesting.expectOne(r => r.url === '/api/identity/v1/vk/authorize');
    expect(request.request.params.get('returnTo')).toBe('/cart');
    request.flush({ url: 'https://id.example.test/vk/authorize' });
  });

  it('reads linked identities from one endpoint for every provider', () => {
    gateway.listIdentities().subscribe();

    const request = httpTesting.expectOne('/api/identity/v1/me/identities');
    expect(request.request.method).toBe('GET');
    request.flush([]);
  });

  it('unlinks an OAuth provider by its identity name', () => {
    gateway.unlink('yandex_id').subscribe();

    const request = httpTesting.expectOne('/api/identity/v1/yandex_id/unlink');
    expect(request.request.method).toBe('POST');
    request.flush(null);
  });

  it('unlinks a non-OAuth provider too (FH-4.6: Telegram is one identity among several)', () => {
    gateway.unlink('telegram').subscribe();

    const request = httpTesting.expectOne('/api/identity/v1/telegram/unlink');
    expect(request.request.method).toBe('POST');
    request.flush(null);
  });
});
