// src/tests/integration/auth.integration.test.ts
import { describe, it, expect } from 'vitest';
import { loginUser } from '../../services/apiClient';
import { getPool } from '../../services/db/connection.db';

/**
 * @vitest-environment node
 */

/**
 * These are integration tests that verify the authentication flow against a running backend server.
 * Make sure your Express server is running before executing these tests.
 *
 * To run only these tests: `vitest run src/tests/auth.integration.test.ts`
 */
describe('Authentication API Integration', () => {
    // --- START DEBUG LOGGING ---
    // Query the DB from within the test file to see its state.
    getPool().query('SELECT u.user_id, u.email, p.role FROM public.users u JOIN public.profiles p ON u.user_id = p.user_id').then(res => {
        console.log('\n--- [auth.integration.test.ts] Users found in DB from TEST perspective: ---');
        console.table(res.rows);
        console.log('--------------------------------------------------------------------------\n');
    }).catch(err => console.error('--- [auth.integration.test.ts] DB QUERY FAILED ---', err));
    // --- END DEBUG LOGGING ---

    // --- START DEBUG LOGGING ---
    // Log the database connection details as seen by an individual TEST FILE.
    console.log('\n\n--- [AUTH.INTEGRATION.TEST LOG] DATABASE CONNECTION ---');
    console.log(`  Host: ${process.env.DB_HOST}`);
    console.log(`  Port: ${process.env.DB_PORT}`);
    console.log(`  User: ${process.env.DB_USER}`);
    console.log(`  Database: ${process.env.DB_NAME}`);
    console.log('-----------------------------------------------------\n');
    // --- END DEBUG LOGGING ---

    // This test migrates the logic from the old DevTestRunner.tsx component.
    it('should successfully log in the admin user', async () => {
        // Note: The admin user must be seeded in your PostgreSQL database for this test to pass.
        // The password here is the plain text password, not the hash.
        const adminEmail = 'admin@example.com';
        const adminPassword = 'adminpass'; // This must match the password in `seed_admin_account.ts`

        // The `rememberMe` parameter is required. For a test, `false` is a safe default.
        const response = await loginUser(adminEmail, adminPassword, false);
        const data = await response.json();

        // Assert that the API returns the expected structure
        expect(data).toBeDefined();
        expect(data.user).toBeDefined();
        expect(data.user.email).toBe(adminEmail);
        expect(data.user.user_id).toBeTypeOf('string');
        expect(data.token).toBeTypeOf('string');
    });

    it('should fail to log in with an incorrect password', async () => {
        const adminEmail = 'admin@example.com';
        const wrongPassword = 'wrongpassword';

        // The loginUser function returns a Response object. We check its status.
        const response = await loginUser(adminEmail, wrongPassword, false);
        expect(response.ok).toBe(false);
        const errorData = await response.json();
        expect(errorData.message).toBe('Incorrect email or password.');
    });

    it('should fail to log in with a non-existent email', async () => {
        const nonExistentEmail = 'nobody-here@example.com';
        const anyPassword = 'any-password';

        // The loginUser function returns a Response object. We check its status.
        const response = await loginUser(nonExistentEmail, anyPassword, false);
        expect(response.ok).toBe(false);
        const errorData = await response.json();
        // Security best practice: the error message should be identical for wrong password and wrong email
        // to prevent user enumeration attacks.
        expect(errorData.message).toBe('Incorrect email or password.');
    });


    it('should successfully refresh an access token using a refresh token cookie', async () => {
        // Arrange: Log in to get a fresh, valid refresh token cookie for this specific test.
        // This ensures the test is self-contained and not affected by other tests.
        const loginResponse = await loginUser('admin@example.com', 'adminpass', true);
        const setCookieHeader = loginResponse.headers.get('set-cookie');
        const refreshTokenCookie = setCookieHeader?.split(';')[0];

        expect(refreshTokenCookie).toBeDefined();

        // Act: Make a request to the refresh-token endpoint, including the cookie.
        const apiUrl = process.env.VITE_API_BASE_URL || 'http://localhost:3001/api';
        const response = await fetch(`${apiUrl}/auth/refresh-token`, {
            method: 'POST',
            headers: {
                'Cookie': refreshTokenCookie!,
            },
        });

        // Assert: Check for a successful response and a new access token.
        expect(response.ok).toBe(true);
        const data = await response.json();
        expect(data.token).toBeTypeOf('string');
    });

    it('should fail to refresh an access token with an invalid refresh token cookie', async () => {
        // Arrange: Create a fake/invalid cookie.
        const invalidRefreshTokenCookie = 'refreshToken=this-is-not-a-valid-token';

        // Act: Make a request to the refresh-token endpoint with the invalid cookie.
        const apiUrl = process.env.VITE_API_BASE_URL || 'http://localhost:3001/api';
        const response = await fetch(`${apiUrl}/auth/refresh-token`, {
            method: 'POST',
            headers: {
                'Cookie': invalidRefreshTokenCookie,
            },
        });

        // Assert: Check for a 403 Forbidden response.
        expect(response.ok).toBe(false);
        expect(response.status).toBe(403);
        const data = await response.json();
        expect(data.message).toBe('Invalid or expired refresh token.');
    });

    it('should successfully log out and clear the refresh token cookie', async () => {
        // Arrange: Log in to get a valid refresh token cookie.
        const loginResponse = await loginUser('admin@example.com', 'adminpass', true);
        const setCookieHeader = loginResponse.headers.get('set-cookie');
        const refreshTokenCookie = setCookieHeader?.split(';')[0];
        expect(refreshTokenCookie).toBeDefined();

        // Act: Make a request to the new logout endpoint, including the cookie.
        const apiUrl = process.env.VITE_API_BASE_URL || 'http://localhost:3001/api';
        const response = await fetch(`${apiUrl}/auth/logout`, {
            method: 'POST',
            headers: {
                'Cookie': refreshTokenCookie!,
            },
        });

        // Assert: Check for a successful response and a cookie-clearing header.
        expect(response.ok).toBe(true);
        const logoutSetCookieHeader = response.headers.get('set-cookie');
        expect(logoutSetCookieHeader).toContain('refreshToken=;');
        expect(logoutSetCookieHeader).toContain('Max-Age=0');
    });
});