import { describe, it, expect, vi, beforeEach } from 'vitest';

// Mock apiClient
vi.mock('../client', () => ({
  default: {
    post: vi.fn(),
    get: vi.fn(),
  },
}));

import {
  login,
  logout,
  getCurrentUser,
  refreshToken,
  masquerade,
  stopMasquerade,
} from '../auth';
import apiClient from '../client';

describe('auth API', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('login', () => {
    it('sends credentials to login endpoint', async () => {
      const mockResponse = {
        data: {
          access: 'access-token',
          refresh: 'refresh-token',
          user: { id: 1, email: 'test@example.com' },
        },
      };
      vi.mocked(apiClient.post).mockResolvedValue(mockResponse);

      const result = await login({ email: 'test@example.com', password: 'password' });

      expect(apiClient.post).toHaveBeenCalledWith('/auth/login/', {
        email: 'test@example.com',
        password: 'password',
      });
      expect(result).toEqual(mockResponse.data);
    });

    it('returns MFA required response', async () => {
      const mockResponse = {
        data: {
          mfa_required: true,
          user_id: 1,
          mfa_methods: ['TOTP', 'SMS'],
        },
      };
      vi.mocked(apiClient.post).mockResolvedValue(mockResponse);

      const result = await login({ email: 'test@example.com', password: 'password' });

      expect(result.mfa_required).toBe(true);
      expect(result.mfa_methods).toContain('TOTP');
    });
  });

  describe('logout', () => {
    it('calls logout endpoint', async () => {
      vi.mocked(apiClient.post).mockResolvedValue({});

      await logout();

      expect(apiClient.post).toHaveBeenCalledWith('/auth/logout/');
    });
  });

  describe('getCurrentUser', () => {
    it('fetches current user from API', async () => {
      const mockUser = {
        id: 1,
        email: 'test@example.com',
        name: 'Test User',
        role: 'owner',
      };
      vi.mocked(apiClient.get).mockResolvedValue({ data: mockUser });

      const result = await getCurrentUser();

      expect(apiClient.get).toHaveBeenCalledWith('/auth/me/');
      expect(result).toEqual(mockUser);
    });
  });

  describe('refreshToken', () => {
    it('sends refresh token to API', async () => {
      const mockResponse = { data: { access: 'new-access-token' } };
      vi.mocked(apiClient.post).mockResolvedValue(mockResponse);

      const result = await refreshToken('old-refresh-token');

      expect(apiClient.post).toHaveBeenCalledWith('/auth/refresh/', {
        refresh: 'old-refresh-token',
      });
      expect(result.access).toBe('new-access-token');
    });
  });

  describe('masquerade', () => {
    it('sends masquerade request with user_pk', async () => {
      const mockResponse = {
        data: {
          access: 'masq-access',
          refresh: 'masq-refresh',
          user: { id: 2, email: 'other@example.com' },
          masquerade_stack: [{ user_id: 1, username: 'admin', role: 'superuser' }],
        },
      };
      vi.mocked(apiClient.post).mockResolvedValue(mockResponse);

      const result = await masquerade(2);

      expect(apiClient.post).toHaveBeenCalledWith('/auth/hijack/acquire/', {
        user_pk: 2,
        hijack_history: undefined,
      });
      expect(result.masquerade_stack).toHaveLength(1);
    });

    it('sends masquerade request with history', async () => {
      const history = [{ user_id: 1, username: 'admin', role: 'superuser' as const }];
      vi.mocked(apiClient.post).mockResolvedValue({ data: {} });

      await masquerade(2, history);

      expect(apiClient.post).toHaveBeenCalledWith('/auth/hijack/acquire/', {
        user_pk: 2,
        hijack_history: history,
      });
    });
  });

  describe('stopMasquerade', () => {
    it('sends release request with masquerade stack', async () => {
      const stack = [{ user_id: 1, username: 'admin', role: 'superuser' as const }];
      const mockResponse = {
        data: {
          access: 'orig-access',
          refresh: 'orig-refresh',
          user: { id: 1 },
          masquerade_stack: [],
        },
      };
      vi.mocked(apiClient.post).mockResolvedValue(mockResponse);

      const result = await stopMasquerade(stack);

      expect(apiClient.post).toHaveBeenCalledWith('/auth/hijack/release/', {
        masquerade_stack: stack,
      });
      expect(result.masquerade_stack).toHaveLength(0);
    });
  });
});
