import path from "path";

export const SUITE_TYPES = new Set(["int", "integration", "e2e", "dal", "load", "all"]);
export const LIFECYCLE = new Set(["status", "destroy"]);
export const RESERVED = new Set([...SUITE_TYPES, ...LIFECYCLE]);

export function resolveCliSelection({ first, second, serviceNames }) {
  let service = null;
  let type = null;

  if (first && serviceNames.has(first)) {
    service = first;
    type = second || null;
  } else if (first && RESERVED.has(first)) {
    type = first;
  } else if (first) {
    throw new Error(
      `Unknown argument "${first}". Expected a service name (${[...serviceNames].join(", ") || "none found"}) ` +
      `or suite type (int, e2e, dal, all).`
    );
  }

  return { service, type };
}

export function validateFrameworkOption(value) {
  if (!["all", "default", "playwright"].includes(value)) {
    throw new Error(
      `Unknown framework "${value}". Expected one of: all, default, playwright.`
    );
  }
  return value === "default" ? "k6" : value;
}

export function parseJobsOption(value) {
  const jobs = Number.parseInt(String(value), 10);
  if (!Number.isInteger(jobs) || jobs <= 0) {
    throw new Error(`Invalid --jobs value "${value}". Expected a positive integer.`);
  }
  return jobs;
}

export function parseShardOption(value) {
  if (!value) return null;

  const match = String(value).match(/^(\d+)\/(\d+)$/);
  if (!match) {
    throw new Error(
      `Invalid --shard value "${value}". Expected the form "i/n", e.g. 1/3.`
    );
  }

  const index = Number.parseInt(match[1], 10);
  const total = Number.parseInt(match[2], 10);
  if (index <= 0 || total <= 0 || index > total) {
    throw new Error(`Invalid --shard value "${value}". Expected 1 <= i <= n.`);
  }

  return { index, total };
}

export function resolveRequestedFiles(fileNames, productDir, invocationCwd = process.cwd()) {
  const resolved = [];
  const seen = new Set();

  for (const rawFile of fileNames || []) {
    const normalized = resolveRequestedFile(rawFile, productDir, invocationCwd);
    if (seen.has(normalized)) continue;
    seen.add(normalized);
    resolved.push(normalized);
  }

  return resolved;
}

function resolveRequestedFile(rawFile, productDir, invocationCwd) {
  const rawValue = String(rawFile);
  const candidates = path.isAbsolute(rawValue)
    ? [rawValue]
    : [path.resolve(invocationCwd, rawValue), path.resolve(productDir, rawValue)];

  for (const candidate of candidates) {
    const relative = normalizePathSeparators(path.relative(productDir, candidate));
    if (!relative.startsWith("../") && relative !== ".." && !path.isAbsolute(relative)) {
      return relative.replace(/^\.\/+/, "");
    }
  }

  return normalizePathSeparators(rawValue).replace(/^\.\/+/, "");
}

function normalizePathSeparators(filePath) {
  return String(filePath).split(path.sep).join("/");
}
