import { vi, Mock } from 'vitest';
import { ClearSessionUseCase } from './ClearSessionUseCase';
import type { AuthenticationServicePort } from '../ports/AuthenticationServicePort';
import type { Logger } from '@core/shared/application';
import { Result } from '@core/shared/application/Result';

describe('ClearSessionUseCase', () => {
  let useCase: ClearSessionUseCase;
  let authService: AuthenticationServicePort;
  let logger: Logger;

  beforeEach(() => {
    const mockAuthService = {
      clearSession: vi.fn(),
      checkSession: vi.fn(),
      initiateLogin: vi.fn(),
      getState: vi.fn(),
      validateServerSide: vi.fn(),
      refreshSession: vi.fn(),
      getSessionExpiry: vi.fn(),
      verifyPageAuthentication: vi.fn(),
    };

    const mockLogger = {
      debug: vi.fn(),
      info: vi.fn(),
      warn: vi.fn(),
      error: vi.fn(),
    };

    authService = mockAuthService as unknown as AuthenticationServicePort;
    logger = mockLogger as Logger;

    useCase = new ClearSessionUseCase(authService, logger);
  });

  describe('execute', () => {
    it('should clear session successfully and return ok result', async () => {
      const successResult = Result.ok<void>(undefined);
      (authService.clearSession as Mock).mockResolvedValue(successResult);

      const result = await useCase.execute();

      expect(authService.clearSession).toHaveBeenCalledTimes(1);
      expect(logger.debug).toHaveBeenCalledWith('Attempting to clear user session.', {
        useCase: 'ClearSessionUseCase'
      });
      expect(logger.info).toHaveBeenCalledWith('User session cleared successfully.', {
        useCase: 'ClearSessionUseCase'
      });
      expect(result.isOk()).toBe(true);
    });

    it('should handle clearSession failure and return err result', async () => {
      const error = new Error('Clear session failed');
      const failureResult = Result.err<void>(error);
      (authService.clearSession as Mock).mockResolvedValue(failureResult);

      const result = await useCase.execute();

      expect(authService.clearSession).toHaveBeenCalledTimes(1);
      expect(logger.debug).toHaveBeenCalledWith('Attempting to clear user session.', {
        useCase: 'ClearSessionUseCase'
      });
      expect(logger.warn).toHaveBeenCalledWith('Failed to clear user session.', {
        useCase: 'ClearSessionUseCase',
        error: error,
      });
      expect(result.isErr()).toBe(true);
      expect(result.error).toBe(error);
    });

    it('should handle unexpected errors and return err result with Error', async () => {
      const thrownError = new Error('Unexpected error');
      (authService.clearSession as Mock).mockRejectedValue(thrownError);

      const result = await useCase.execute();

      expect(authService.clearSession).toHaveBeenCalledTimes(1);
      expect(logger.debug).toHaveBeenCalledWith('Attempting to clear user session.', {
        useCase: 'ClearSessionUseCase'
      });
      expect(logger.error).toHaveBeenCalledWith('Error clearing user session.', thrownError, {
        useCase: 'ClearSessionUseCase'
      });
      expect(result.isErr()).toBe(true);
      expect(result.error).toBeInstanceOf(Error);
      expect(result.error?.message).toBe('Unexpected error');
    });

    it('should handle non-Error thrown values and convert to Error', async () => {
      const thrownValue = 'String error';
      (authService.clearSession as Mock).mockRejectedValue(thrownValue);

      const result = await useCase.execute();

      expect(authService.clearSession).toHaveBeenCalledTimes(1);
      expect(logger.error).toHaveBeenCalledWith('Error clearing user session.', expect.any(Error), {
        useCase: 'ClearSessionUseCase'
      });
      expect(result.isErr()).toBe(true);
      expect(result.error).toBeInstanceOf(Error);
      expect(result.error?.message).toBe('String error');
    });
  });
});