import { TestBed } from '@angular/core/testing';
import { Observable, of, throwError } from 'rxjs';
import { AccountIdentitiesComponent } from './account-identities.component';
import { SOCIAL_IDENTITY_GATEWAY } from '../../../../core/identity/services/social-identity-gateway.token';
import { SocialIdentityGateway } from '../../../../core/identity/services/social-identity-gateway.interface';
import {
  ExternalIdentity,
  ExternalIdentityProvider,
} from '../../../../core/identity/models/customer-identity.model';

function identity(provider: ExternalIdentityProvider): ExternalIdentity {
  return {
    customerId: 'c1',
    provider,
    providerUserId: 'u_' + provider,
    verifiedAt: '2026-08-01T00:00:00.000Z',
    lastUsedAt: '2026-08-21T00:00:00.000Z',
  };
}

class FakeGateway implements SocialIdentityGateway {
  linked: ExternalIdentity[] = [];
  unlinkCalls: ExternalIdentityProvider[] = [];
  failList = false;

  getAuthorizeUrl(): Observable<string> {
    return of('about:blank');
  }
  listIdentities(): Observable<ExternalIdentity[]> {
    return this.failList ? throwError(() => new Error('boom')) : of(this.linked);
  }
  unlink(provider: ExternalIdentityProvider): Observable<void> {
    this.unlinkCalls.push(provider);
    return of(void 0);
  }
}

function make(gateway: FakeGateway): AccountIdentitiesComponent {
  TestBed.configureTestingModule({
    providers: [{ provide: SOCIAL_IDENTITY_GATEWAY, useValue: gateway }],
  });
  return TestBed.createComponent(AccountIdentitiesComponent).componentInstance;
}

describe('AccountIdentitiesComponent', () => {
  it('lists the linked identities and reports ready', () => {
    const g = new FakeGateway();
    g.linked = [identity('telegram'), identity('vk_id')];
    const c = make(g);

    expect(c.state()).toBe('ready');
    expect(c.identities().map(i => i.provider)).toEqual(['telegram', 'vk_id']);
  });

  it('offers only the OAuth providers that are not already linked', () => {
    const g = new FakeGateway();
    g.linked = [identity('vk_id')]; // vk linked, yandex not
    const c = make(g);

    expect(c.linkable()).toEqual(['yandex']);
  });

  it('refuses to unlink the last remaining identity', () => {
    const g = new FakeGateway();
    g.linked = [identity('telegram')];
    const c = make(g);

    expect(c.isLastIdentity()).toBe(true);
    c.unlink('telegram');

    expect(g.unlinkCalls).toEqual([]);
    expect(c.identities().length).toBe(1);
  });

  it('unlinks a provider when more than one is linked', () => {
    const g = new FakeGateway();
    g.linked = [identity('telegram'), identity('vk_id')];
    const c = make(g);

    c.unlink('vk_id');

    expect(g.unlinkCalls).toEqual(['vk_id']);
    expect(c.identities().map(i => i.provider)).toEqual(['telegram']);
  });

  it('surfaces a load failure instead of showing an empty account', () => {
    const g = new FakeGateway();
    g.failList = true;
    const c = make(g);

    expect(c.state()).toBe('error');
  });
});
