import type { Logger } from '@core/shared/domain/Logger';
import { describe, expect, it, vi, type Mock } from 'vitest';
import type { IdentityProviderPort } from '../ports/IdentityProviderPort';
import { StartAuthUseCase } from './StartAuthUseCase';

describe('StartAuthUseCase', () => {
  let provider: {
    startAuth: Mock;
  };
  let logger: Logger & { error: Mock };
  let useCase: StartAuthUseCase;

  beforeEach(() => {
    provider = {
      startAuth: vi.fn(),
    };

    logger = {
      debug: vi.fn(),
      info: vi.fn(),
      warn: vi.fn(),
      error: vi.fn(),
    } as unknown as Logger & { error: Mock };

    useCase = new StartAuthUseCase(
      provider as unknown as IdentityProviderPort,
      logger,
    );
  });

  it('returns ok and presents redirect when provider call succeeds', async () => {
    provider.startAuth.mockResolvedValue({
      redirectUrl: 'https://auth/redirect',
      state: 'state-123',
    });

    const result = await useCase.execute({
      provider: 'iracing',
      returnTo: '/dashboard',
    });

    expect(result.isOk()).toBe(true);
    const startAuthResult = result.unwrap();
    expect(startAuthResult.redirectUrl).toBe('https://auth/redirect');
    expect(startAuthResult.state).toBe('state-123');
    expect(provider.startAuth).toHaveBeenCalledWith({
      provider: 'iracing',
      returnTo: '/dashboard',
    });
  });

  it('returns ok without returnTo when not provided', async () => {
    provider.startAuth.mockResolvedValue({
      redirectUrl: 'https://auth/redirect',
      state: 'state-123',
    });

    const result = await useCase.execute({
      provider: 'iracing',
    });

    expect(result.isOk()).toBe(true);
    expect(provider.startAuth).toHaveBeenCalledWith({
      provider: 'iracing',
    });
  });

  it('returns error when provider call fails', async () => {
    provider.startAuth.mockRejectedValue(new Error('Provider error'));

    const result = await useCase.execute({
      provider: 'iracing',
    });

    expect(result.isErr()).toBe(true);
    expect(result.unwrapErr().code).toBe('REPOSITORY_ERROR');
    expect(logger.error).toHaveBeenCalled();
  });
});