// src/tests/utils/testHelpers.ts
import * as apiClient from '../../services/apiClient';
import { getPool } from '../../services/db/connection.db';
import type { UserProfile } from '../../types';
import supertest from 'supertest';

export const TEST_PASSWORD = 'a-much-stronger-password-for-testing-!@#$';
export const TEST_EXAMPLE_DOMAIN = 'https://example.com';

export const getTestBaseUrl = (): string => {
  const url = process.env.FRONTEND_URL || `https://example.com`;
  return url.endsWith('/') ? url.slice(0, -1) : url;
};

interface CreateUserOptions {
  email?: string;
  password?: string;
  fullName?: string;
  role?: 'admin' | 'user';
  // Use ReturnType to match the actual return type of supertest(app) to avoid type mismatches (e.g. TestAgent vs SuperTest)
  request?: ReturnType<typeof supertest>;
}

interface CreateUserResult {
  user: UserProfile;
  token: string;
}

/**
 * A helper function for integration tests to create a new user and log them in.
 * This provides an authenticated context for testing protected API endpoints.
 *
 * @param options Optional parameters to customize the user.
 * @returns A promise that resolves to an object containing the user and auth token.
 */
export const createAndLoginUser = async (
  options: CreateUserOptions = {},
): Promise<CreateUserResult> => {
  const email = options.email || `test-user-${Date.now()}@example.com`;
  const password = options.password || TEST_PASSWORD;
  const fullName = options.fullName || 'Test User';

  if (options.request) {
    // Use supertest for integration tests (hits the app instance directly)
    const registerRes = await options.request
      .post('/api/auth/register')
      .send({ email, password, full_name: fullName });

    if (registerRes.status !== 201 && registerRes.status !== 200) {
      throw new Error(
        `Failed to register user via supertest: ${registerRes.status} ${JSON.stringify(registerRes.body)}`,
      );
    }

    if (options.role === 'admin') {
      await getPool().query(
        `UPDATE public.profiles SET role = 'admin' FROM public.users WHERE public.profiles.user_id = public.users.user_id AND public.users.email = $1`,
        [email],
      );
    }

    const loginRes = await options.request
      .post('/api/auth/login')
      .send({ email, password, rememberMe: false });

    if (loginRes.status !== 200) {
      throw new Error(
        `Failed to login user via supertest: ${loginRes.status} ${JSON.stringify(loginRes.body)}`,
      );
    }

    const { userprofile, token } = loginRes.body.data;
    return { user: userprofile, token };
  } else {
    // Use apiClient for E2E tests (hits the external URL via fetch)
    await apiClient.registerUser(email, password, fullName);

    if (options.role === 'admin') {
      await getPool().query(
        `UPDATE public.profiles SET role = 'admin' FROM public.users WHERE public.profiles.user_id = public.users.user_id AND public.users.email = $1`,
        [email],
      );
    }

    const loginResponse = await apiClient.loginUser(email, password, false);
    if (!loginResponse.ok) {
      throw new Error(`Failed to login user via apiClient: ${loginResponse.status}`);
    }
    const responseData = await loginResponse.json();
    const { userprofile, token } = responseData.data;
    return { user: userprofile, token };
  }
};
