import { readFileSync } from "node:fs";
import { gzipSync } from "node:zlib";

import { rootPath } from "./config";
import { loadCicdOtelRuntimeConfig } from "../native/cicd/otel-runtime-config";

const validatorSource = readFileSync(rootPath("scripts/native/cicd/feature-config-schema-warning.mjs"), "utf8").trimEnd();
const ajv2020BundleSource = readFileSync(rootPath("scripts/vendor/ajv-dist/8.17.1/ajv2020.min.js"), "utf8").trimEnd();
const validatorGzipBase64 = gzipBase64(validatorSource);
const ajv2020GzipBase64 = gzipBase64(ajv2020BundleSource);

export interface PacFeatureConfigSchemaStageOptions {
  readonly repositoryId: string;
  readonly consumer: string;
  readonly repoDirExpression: string;
  readonly renderedRootExpression: string;
  readonly ajvBundleExpression?: string | null;
}

export function renderPacFeatureConfigSchemaStage(options: PacFeatureConfigSchemaStageOptions): string {
  const otel = loadCicdOtelRuntimeConfig(options.repositoryId);
  const materializeBundle = options.ajvBundleExpression === undefined || options.ajvBundleExpression === null;
  return [
    "feature_config_schema_started_ms=\"$(date +%s%3N 2>/dev/null || date +%s000)\"",
    `export UNIDESK_FEATURE_CONFIG_REPO_DIR=${options.repoDirExpression}`,
    `export UNIDESK_FEATURE_CONFIG_RENDERED_ROOT=${options.renderedRootExpression}`,
    `export UNIDESK_PAC_CONSUMER=${shellSingle(options.consumer)}`,
    `export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=${shellSingle(otel.endpoint)}`,
    `export OTEL_SERVICE_NAME=${shellSingle(otel.serviceName)}`,
    `export OTEL_TRACES_SAMPLER_ARG=${shellSingle(String(otel.samplingRatio))}`,
    `export OTEL_EXPORTER_TIMEOUT_MS=${shellSingle(String(otel.timeoutMs))}`,
    "feature_config_validator_base=''",
    "feature_config_validator=''",
    "if feature_config_validator_base=\"$(mktemp \"${TMPDIR:-/tmp}/unidesk-feature-config-validator.XXXXXX\" 2>/dev/null)\"; then",
    "  feature_config_validator=\"${feature_config_validator_base}.mjs\"",
    "  if ! printf '%s' " + shellSingle(validatorGzipBase64) + " | base64 -d | gzip -d >\"$feature_config_validator\"; then",
    "    rm -f \"$feature_config_validator_base\" \"$feature_config_validator\" || true",
    "    feature_config_validator=''",
    "  fi",
    "  rm -f \"$feature_config_validator_base\" || true",
    "fi",
    ...(materializeBundle
      ? [
        "feature_config_ajv_bundle=''",
        "if feature_config_ajv_bundle=\"$(mktemp \"${TMPDIR:-/tmp}/unidesk-ajv2020.XXXXXX\" 2>/dev/null)\"; then",
        "  if ! printf '%s' " + shellSingle(ajv2020GzipBase64) + " | base64 -d | gzip -d >\"$feature_config_ajv_bundle\"; then",
        "    rm -f \"$feature_config_ajv_bundle\" || true",
        "    feature_config_ajv_bundle=''",
        "  fi",
        "fi",
        "export UNIDESK_AJV2020_BUNDLE=\"${feature_config_ajv_bundle:-${TMPDIR:-/tmp}/unidesk-ajv2020-unavailable}\"",
      ]
      : [`export UNIDESK_AJV2020_BUNDLE=${options.ajvBundleExpression}`]),
    "export UNIDESK_FEATURE_CONFIG_VALIDATOR=\"${feature_config_validator:-${TMPDIR:-/tmp}/unidesk-feature-config-validator-unavailable.mjs}\"",
    "if ! node --input-type=module <<'NODE_UNIDESK_FEATURE_CONFIG_SCHEMA'",
    "import { pathToFileURL } from 'node:url';",
    "const validator = await import(pathToFileURL(process.env.UNIDESK_FEATURE_CONFIG_VALIDATOR).href);",
    "await validator.runFeatureConfigSchemaValidation({ repoDir: process.env.UNIDESK_FEATURE_CONFIG_REPO_DIR, renderedRoot: process.env.UNIDESK_FEATURE_CONFIG_RENDERED_ROOT, consumer: process.env.UNIDESK_PAC_CONSUMER });",
    "NODE_UNIDESK_FEATURE_CONFIG_SCHEMA",
    "then",
    "  printf '{\"event\":\"feature-config-schema-validation\",\"warning\":true,\"blocking\":false,\"code\":\"feature-config-validator-process-failure\",\"mutation\":false,\"valuesPrinted\":false}\\n' >&2",
    "fi",
    "if [ -n \"$feature_config_validator\" ]; then rm -f \"$feature_config_validator\" || true; fi",
    ...(materializeBundle ? ["if [ -n \"$feature_config_ajv_bundle\" ]; then rm -f \"$feature_config_ajv_bundle\" || true; fi"] : []),
    "if command -v ci_timing_emit >/dev/null 2>&1; then",
    "  ci_timing_emit feature-config-schema-validation succeeded \"$feature_config_schema_started_ms\"",
    "else",
    "  printf '{\"event\":\"ci.stage.timing\",\"stage\":\"feature-config-schema-validation\",\"status\":\"succeeded\",\"blocking\":false}\\n' >&2",
    "fi",
  ].join("\n");
}

function shellSingle(value: string): string {
  return `'${value.replaceAll("'", `'"'"'`)}'`;
}

function gzipBase64(value: string): string {
  return gzipSync(Buffer.from(value, "utf8"), { level: 9 }).toString("base64");
}
