import { TestFactory } from '../../../__tests__/factories';
import { AuthController } from '../auth.controller';
import { authService } from '../auth.service';

// Mock dependencies
jest.mock('../auth.service');

describe('AuthController', () => {
    let authController: AuthController;
    let mockReq: any;
    let mockRes: any;

    beforeEach(() => {
        jest.clearAllMocks();
        authController = new AuthController();

        mockReq = {
            body: {},
            ip: '127.0.0.1',
            headers: {},
        };

        mockRes = {
            status: jest.fn().mockReturnThis(),
            json: jest.fn().mockReturnThis(),
            cookie: jest.fn().mockReturnThis(),
        };
    });

    describe('register', () => {
        it('should register user and return 201', async () => {
            mockReq.body = { email: 'test@example.com', password: 'Password123!' };
            const mockResult = {
                user: TestFactory.createUser(),
                tokens: { accessToken: 'access', refreshToken: 'refresh' },
            };

            (authService.register as jest.Mock).mockResolvedValue(mockResult);

            await authController.register(mockReq, mockRes);

            expect(authService.register).toHaveBeenCalledWith(expect.anything(), mockReq);
            expect(mockRes.status).toHaveBeenCalledWith(201);
            expect(mockRes.json).toHaveBeenCalledWith({
                success: true,
                data: expect.anything(),
            });
        });

        it('should return 400 if registration fails', async () => {
            // Pass valid body to pass Zod, but fail later
            mockReq.body = { email: 'test@example.com', password: 'Password123!' };
            const error = new Error('Registration failed');
            (authService.register as jest.Mock).mockRejectedValue(error);

            await authController.register(mockReq, mockRes);

            expect(mockRes.status).toHaveBeenCalledWith(400);
            expect(mockRes.json).toHaveBeenCalledWith(expect.objectContaining({
                success: false,
                error: expect.objectContaining({ message: 'Registration failed' })
            }));
        });
    });

    describe('login', () => {
        it('should login user and return 200', async () => {
            mockReq.body = { email: 'test@example.com', password: 'Password123!' };
            const mockResult = {
                user: TestFactory.createUser(),
                tokens: { accessToken: 'access', refreshToken: 'refresh' },
            };

            (authService.login as jest.Mock).mockResolvedValue(mockResult);

            await authController.login(mockReq, mockRes);

            expect(authService.login).toHaveBeenCalledWith(expect.anything(), mockReq);
            expect(mockRes.status).toHaveBeenCalledWith(200);
            expect(mockRes.json).toHaveBeenCalledWith({
                success: true,
                data: expect.anything(),
            });
        });

        it('should handle MFA required response', async () => {
            mockReq.body = { email: 'test@example.com', password: 'Password123!' };
            const mockMfaResult = {
                user: { ...TestFactory.createUser(), mfaRequired: true },
                tokens: { accessToken: '', refreshToken: '' }, // Type requires tokens
            };
            (authService.login as jest.Mock).mockResolvedValue(mockMfaResult);

            await authController.login(mockReq, mockRes);

            expect(mockRes.status).toHaveBeenCalledWith(200);
            expect(mockRes.json).toHaveBeenCalledWith({
                success: true,
                data: expect.objectContaining({ mfaRequired: true }),
            });
        });

        it('should return 401 if login fails', async () => {
            mockReq.body = { email: 'test@example.com', password: 'Password123!' };
            const error = new Error('Invalid credentials');
            (authService.login as jest.Mock).mockRejectedValue(error);

            await authController.login(mockReq, mockRes);

            expect(mockRes.status).toHaveBeenCalledWith(401);
            expect(mockRes.json).toHaveBeenCalledWith(expect.objectContaining({
                success: false,
                error: expect.objectContaining({ code: 'LOGIN_FAILED' })
            }));
        });
    });
});
