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

describe('HandleAuthCallbackUseCase', () => {
  let provider: {
    completeAuth: Mock;
  };
  let sessionPort: {
    createSession: Mock;
  };
  let logger: Logger & { error: Mock };
  let useCase: HandleAuthCallbackUseCase;

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

    sessionPort = {
      createSession: vi.fn(),
    };

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

    useCase = new HandleAuthCallbackUseCase(
      provider as unknown as IdentityProviderPort,
      sessionPort as unknown as IdentitySessionPort,
      logger,
    );
  });

  it('successfully handles auth callback and creates session', async () => {
    const authenticatedUser = {
      id: 'user-1',
      displayName: 'Test User',
      email: 'test@example.com',
    };
    const session = {
      token: 'session-token',
      user: authenticatedUser,
      issuedAt: Date.now(),
      expiresAt: Date.now() + 1000,
    };

    provider.completeAuth.mockResolvedValue(authenticatedUser);
    sessionPort.createSession.mockResolvedValue(session);

    const result = await useCase.execute({
      code: 'auth-code',
      state: 'state-123',
      returnTo: '/dashboard',
    });

    expect(result.isOk()).toBe(true);
    const callbackResult = result.unwrap();
    expect(callbackResult.token).toBe('session-token');
    expect(callbackResult.user).toBe(authenticatedUser);
    expect(provider.completeAuth).toHaveBeenCalledWith({
      code: 'auth-code',
      state: 'state-123',
      returnTo: '/dashboard',
    });
    expect(sessionPort.createSession).toHaveBeenCalledWith(authenticatedUser);
  });

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

    const result = await useCase.execute({
      code: 'invalid-code',
      state: 'state-123',
    });

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

  it('returns error when session creation fails', async () => {
    const authenticatedUser = {
      id: 'user-1',
      displayName: 'Test User',
      email: 'test@example.com',
    };

    provider.completeAuth.mockResolvedValue(authenticatedUser);
    sessionPort.createSession.mockRejectedValue(new Error('Session creation failed'));

    const result = await useCase.execute({
      code: 'auth-code',
      state: 'state-123',
    });

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