import { readFileSync, existsSync } from "node:fs";
import { resolve } from "node:path";

const DEFAULT_TIMEOUT_MS = 20000;
const DEFAULT_ENDPOINT = "/tender/SCRZJ";

function parseBoolean(value, fallback = false) {
  if (!value) {
    return fallback;
  }

  const normalized = value.trim().toLowerCase();

  if (["1", "true", "yes", "si"].includes(normalized)) {
    return true;
  }

  if (["0", "false", "no"].includes(normalized)) {
    return false;
  }

  return fallback;
}

function loadDotenv(filePath) {
  if (!existsSync(filePath)) {
    return;
  }

  const raw = readFileSync(filePath, "utf8");

  for (const line of raw.split(/\r?\n/)) {
    const trimmed = line.trim();

    if (!trimmed || trimmed.startsWith("#")) {
      continue;
    }

    const eqIndex = trimmed.indexOf("=");
    if (eqIndex === -1) {
      continue;
    }

    const key = trimmed.slice(0, eqIndex).trim();
    if (!key || process.env[key] !== undefined) {
      continue;
    }

    let value = trimmed.slice(eqIndex + 1).trim();

    if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
      value = value.slice(1, -1);
    }

    process.env[key] = value;
  }
}

function parseArgs(argv) {
  const args = {
    baseUrl: process.env.LICITAYA_BASE_URL,
    endpoint: process.env.LICITAYA_TEST_ENDPOINT || DEFAULT_ENDPOINT,
    accept: process.env.LICITAYA_ACCEPT || "application/json",
    method: "GET",
    timeoutMs: Number.parseInt(process.env.LICITAYA_TIMEOUT_MS || "", 10) || DEFAULT_TIMEOUT_MS,
    allowEmptySearch: parseBoolean(process.env.LICITAYA_ALLOW_EMPTY_SEARCH, true),
  };

  for (let i = 0; i < argv.length; i += 1) {
    const current = argv[i];
    const next = argv[i + 1];

    if (current === "--base-url" && next) {
      args.baseUrl = next;
      i += 1;
      continue;
    }

    if (current === "--endpoint" && next) {
      args.endpoint = next;
      i += 1;
      continue;
    }

    if (current === "--accept" && next) {
      args.accept = next;
      i += 1;
      continue;
    }

    if (current === "--method" && next) {
      args.method = next.toUpperCase();
      i += 1;
      continue;
    }

    if (current === "--timeout" && next) {
      const parsed = Number.parseInt(next, 10);
      if (Number.isFinite(parsed) && parsed > 0) {
        args.timeoutMs = parsed;
      }
      i += 1;
      continue;
    }

    if (current === "--allow-empty-search") {
      args.allowEmptySearch = true;
      continue;
    }
  }

  return args;
}

function buildUrl(baseUrl, endpoint) {
  if (!endpoint) {
    throw new Error("Missing LICITAYA_TEST_ENDPOINT (or --endpoint).");
  }

  if (endpoint.includes("<") || endpoint.includes(">")) {
    throw new Error(
      "LICITAYA_TEST_ENDPOINT still contains placeholders. Use a real path such as /tender/search or /tender/<tenderId>.",
    );
  }

  if (/^https?:\/\//i.test(endpoint)) {
    return new URL(endpoint);
  }

  if (!baseUrl) {
    throw new Error("Missing LICITAYA_BASE_URL (or --base-url).");
  }

  const normalizedBase = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
  const cleanEndpoint = endpoint.startsWith("/") ? endpoint.slice(1) : endpoint;

  return new URL(cleanEndpoint, normalizedBase);
}

function previewBody(rawBody, contentType) {
  const trimmed = rawBody.trim();

  if (!trimmed) {
    return "(empty body)";
  }

  const isJson = contentType.includes("application/json") || trimmed.startsWith("{") || trimmed.startsWith("[");

  if (isJson) {
    try {
      const json = JSON.parse(trimmed);
      return JSON.stringify(json, null, 2);
    } catch {
      return trimmed.slice(0, 3000);
    }
  }

  return trimmed.slice(0, 3000);
}

loadDotenv(resolve(process.cwd(), ".env"));

const apiKey = process.env.LICITAYA_API_KEY || process.env.X_API_KEY || process.env.X_API_KEY_LICITAYA;
if (!apiKey) {
  console.error("Missing API key. Set LICITAYA_API_KEY in .env or shell env.");
  process.exit(1);
}

const args = parseArgs(process.argv.slice(2));

let url;

try {
  url = buildUrl(args.baseUrl, args.endpoint);
} catch (error) {
  console.error(error instanceof Error ? error.message : String(error));
  process.exit(1);
}

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), args.timeoutMs);

try {
  const response = await fetch(url, {
    method: args.method,
    headers: {
      "X-API-KEY": apiKey,
      Accept: args.accept,
    },
    signal: controller.signal,
  });

  const contentType = response.headers.get("content-type") || "";
  const rawBody = await response.text();
  const bodyPreview = previewBody(rawBody, contentType);

  console.log(`URL: ${url.toString()}`);
  console.log(`Method: ${args.method}`);
  console.log(`Status: ${response.status} ${response.statusText}`);
  console.log(`Content-Type: ${contentType || "(none)"}`);
  console.log("--- Response Preview ---");
  console.log(bodyPreview);

  const isEmptySearch404 = response.status === 404 && url.pathname.endsWith("/tender/search");

  if (isEmptySearch404) {
    console.error("No tenders matched the current filters. Try a broader keyword or fewer filters.");
  }

  if (isEmptySearch404 && args.allowEmptySearch) {
    console.log("Connectivity check passed (search endpoint returned 404 with no matches).");
    process.exit(0);
  }

  if (!response.ok) {
    process.exit(1);
  }
} catch (error) {
  if (error instanceof Error && error.name === "AbortError") {
    console.error(`Request timed out after ${args.timeoutMs} ms.`);
  } else {
    console.error(error instanceof Error ? error.message : String(error));
  }
  process.exit(1);
} finally {
  clearTimeout(timeout);
}
