import { fail } from "k6";
import {
  defaultOptions,
  emitFailureCollectionArtifact,
  recordRuntimeFailure,
  startFailureCollection,
} from "./checks.js";
import { createHttpClient, getEnv } from "./http.js";
import {
  clearRuntimeContext,
  registerRuntimeContext,
  resolveHttpProfile,
} from "../../setup/runtime.mjs";

export function defineHttpSuite(configOrRun, maybeRun) {
  const { config, run } = normalizeSuiteArgs(configOrRun, maybeRun);

  return {
    get options() {
      return mergeProfileConfig(config).options || defaultOptions;
    },
    setup() {
      const resolved = resolveRuntimeConfig(config);
      startFailureCollection("setup");
      try {
        registerRuntimeContext({ env: resolved.env, http: resolved.client.rawHttp || null });
        if (typeof resolved.auth?.setup !== "function") return null;
        return resolved.auth.setup({ env: resolved.env });
      } catch (error) {
        recordRuntimeFailure();
        fail(formatFatalSuiteError("setup", error));
      } finally {
        emitFailureCollectionArtifact();
        clearRuntimeContext();
      }
    },
    exec(setupData) {
      const resolved = resolveRuntimeConfig(config);
      startFailureCollection("exec");
      try {
        registerRuntimeContext({ env: resolved.env, http: resolved.client.rawHttp || null });
        return run({
          env: resolved.env,
          req: resolved.client.request,
          rawReq: resolved.client.raw,
          getWithHeaders: resolved.client.getWithHeaders,
          setupData,
          session: setupData,
        });
      } catch (error) {
        recordRuntimeFailure();
        fail(formatFatalSuiteError("exec", error));
      } finally {
        emitFailureCollectionArtifact();
        clearRuntimeContext();
      }
    },
  };
}

function normalizeSuiteArgs(configOrRun, maybeRun) {
  if (typeof configOrRun === "function") {
    return { config: {}, run: configOrRun };
  }
  if (typeof maybeRun !== "function") {
    throw new Error("suite factory requires a run callback");
  }
  return { config: configOrRun || {}, run: maybeRun };
}

function callHeaders(builder, setupData, env) {
  if (typeof builder !== "function") return {};
  return builder(setupData, { env }) || {};
}

function mergeProfileConfig(config) {
  if (!config?.profile) return config || {};

  const profile = resolveHttpProfile(config.profile) || {};
  return {
    ...profile,
    ...config,
    auth: config.auth ?? profile.auth ?? null,
    headers: config.headers ?? profile.headers,
    rawHeaders: config.rawHeaders ?? profile.rawHeaders,
    options: config.options ?? profile.options,
    env: config.env ?? profile.env,
  };
}

function resolveRuntimeConfig(config) {
  const resolvedConfig = mergeProfileConfig(config);
  const env = {
    ...(resolvedConfig.env || getEnv()),
    rawEnv: __ENV,
  };
  const auth = resolvedConfig.auth || null;
  const client = createHttpClient({
    baseUrl: env.BASE,
    routeHeaders: env.routeParams,
    getHeaders(setupData) {
      return {
        ...callHeaders(auth?.headers, setupData, env),
        ...callHeaders(resolvedConfig.headers, setupData, env),
      };
    },
    getRawHeaders(setupData) {
      return callHeaders(resolvedConfig.rawHeaders, setupData, env);
    },
  });

  return {
    resolvedConfig,
    env,
    auth,
    client,
  };
}

function formatFatalSuiteError(phase, error) {
  if (error instanceof Error) {
    return `Uncaught testkit suite error during ${phase}: ${error.message}`;
  }
  return `Uncaught testkit suite error during ${phase}: ${String(error)}`;
}
