#!/bin/sh
set -eu
# __HWLAB_CI_TIMING_SHELL__

export HWLAB_TEKTON_PIPELINERUN="$(context.pipelineRun.name)"
export HWLAB_TEKTON_TASKRUN="$(context.taskRun.name)"
export HWLAB_TEKTON_TASK="prepare-source"
export HWLAB_SOURCE_REVISION="$(params.revision)"
echo '{"event":"ci-base-image","phase":"prepare-source","image":"__HWLAB_CI_TOOLS_IMAGE__","policy":"no-runtime-apk"}'
for tool in node git timeout; do command -v "$tool" >/dev/null 2>&1 || { echo '{"event":"ci-base-image","ok":false,"reason":"missing-tool","tool":"'"$tool"'"}'; exit 31; }; done
node -e 'console.log(JSON.stringify({event:"ci-base-image",phase:"prepare-source",ok:true,node:process.version}))'
# __HWLAB_GIT_SSH_SHELL__

git_url_requires_ssh() { case "$1" in git@*|ssh://*) return 0 ;; *) return 1 ;; esac; }
git_read_url="$(params.git-read-url)"
if git_url_requires_ssh "$git_read_url"; then
  for tool in ssh ssh-keyscan; do command -v "$tool" >/dev/null 2>&1 || { echo '{"event":"ci-base-image","ok":false,"reason":"missing-tool","tool":"'"$tool"'"}'; exit 31; }; done
  git_ssh_setup
else
  echo '{"event":"git-ssh-setup","phase":"prepare-source","status":"skipped","reason":"non-ssh-git-read-url"}'
fi
rm -rf /workspace/source/repo
source_clone_started_ms="$(ci_now_ms)"
git_timed source-clone 180 git clone --branch "$(params.source-branch)" "$git_read_url" /workspace/source/repo
cd /workspace/source/repo
git config --global --add safe.directory /workspace/source/repo
git remote set-url origin "$git_read_url"
git checkout "$(params.revision)"
test "$(git rev-parse HEAD)" = "$(params.revision)"
git merge-base --is-ancestor "$(params.revision)" "origin/$(params.source-branch)" || { echo '{"event":"source-ancestry","status":"failed","revision":"'"$(params.revision)"'","sourceBranch":"'"$(params.source-branch)"'"}'; exit 32; }
ci_timing_emit source-clone succeeded "$source_clone_started_ms"
prepare_source_dependencies_started_ms="$(ci_now_ms)"
echo '{"event":"prepare-source-dependencies","status":"skipped","reason":"renderer-dependency-install-disabled","dependency":"yaml"}'
ci_timing_emit prepare-source-dependencies succeeded "$prepare_source_dependencies_started_ms"
catalog_path="$(params.catalog-path)"
mkdir -p "$(dirname "$catalog_path")"
catalog_fetch_started_ms="$(ci_now_ms)"
if git_timed catalog-ls-remote 45 git ls-remote --exit-code --heads "$git_read_url" "$(params.gitops-branch)" >/dev/null; then
  git remote set-url gitops-catalog "$git_read_url" 2>/dev/null || git remote add gitops-catalog "$git_read_url"
  git_timed catalog-fetch 90 git fetch --depth 1 gitops-catalog "$(params.gitops-branch)" >/dev/null || true
  if git cat-file -e FETCH_HEAD:"$catalog_path" 2>/dev/null; then
    git show FETCH_HEAD:"$catalog_path" > /tmp/hwlab-gitops-artifact-catalog.json
    if node --input-type=module - /tmp/hwlab-gitops-artifact-catalog.json deploy/deploy.yaml "$(params.services)" <<'NODE'
import fs from "node:fs";
const [catalogPath, deployPath, selectedServices] = process.argv.slice(2);
const ids = (doc) => (doc.services || []).map((service) => service.serviceId).filter(Boolean);
const topLevelServiceIds = (text) => {
  const values = [];
  let inServices = false;
  for (const line of text.split(/\r?\n/u)) {
    if (/^services:\s*$/u.test(line)) { inServices = true; continue; }
    if (!inServices) continue;
    if (/^\S/u.test(line)) break;
    const match = line.match(/^\s*-\s+serviceId:\s*['"]?([^'"#\s]+)['"]?/u);
    if (match) values.push(match[1]);
  }
  return values;
};
const selected = (selectedServices || "").split(",").map((item) => item.trim()).filter(Boolean);
const uniqueSorted = (items) => [...new Set(items)].sort();
const gitops = JSON.parse(fs.readFileSync(catalogPath, "utf8"));
const expected = selected.length ? selected : topLevelServiceIds(fs.readFileSync(deployPath, "utf8"));
const actual = ids(gitops);
const expectedSet = uniqueSorted(expected);
const actualSet = uniqueSorted(actual);
const sameServices = expectedSet.length === actualSet.length && expectedSet.every((item, index) => item === actualSet[index]);
if (!sameServices) {
  const missing = expectedSet.filter((item) => !actualSet.includes(item));
  const extra = actualSet.filter((item) => !expectedSet.includes(item));
  console.error(JSON.stringify({ event: "gitops-artifact-catalog", phase: "prepare-source", status: "ignored-stale", reason: "service-ids-mismatch", expected, actual, missing, extra }));
  process.exit(42);
}
NODE
    then
      cp /tmp/hwlab-gitops-artifact-catalog.json "$catalog_path"
      echo '{"event":"gitops-artifact-catalog","phase":"prepare-source","status":"loaded","branch":"'"$(params.gitops-branch)"'"}'
    else
      echo '{"event":"gitops-artifact-catalog","phase":"prepare-source","status":"ignored-stale","reason":"service-ids-mismatch","branch":"'"$(params.gitops-branch)"'"}'
    fi
  else
    echo '{"event":"gitops-artifact-catalog","phase":"prepare-source","status":"seed","reason":"missing-on-gitops-branch"}'
  fi
else
  echo '{"event":"gitops-artifact-catalog","phase":"prepare-source","status":"seed","reason":"gitops-branch-missing"}'
fi
if [ ! -s "$catalog_path" ] && [ "$(params.lane)" = "v02" ]; then
  node --input-type=module - "$catalog_path" "$(params.revision)" "$(params.registry-prefix)" "$(params.image-tag-mode)" "$(params.services)" <<'NODE'
import fs from 'node:fs';
import path from 'node:path';
const [catalogPath, revision, registryPrefix, imageTagMode, selectedServices] = process.argv.slice(2);
const topLevelServiceIds = (text) => {
  const values = [];
  let inServices = false;
  for (const line of text.split(/\r?\n/u)) {
    if (/^services:\s*$/u.test(line)) { inServices = true; continue; }
    if (!inServices) continue;
    if (/^\S/u.test(line)) break;
    const match = line.match(/^\s*-\s+serviceId:\s*['"]?([^'"#\s]+)['"]?/u);
    if (match) values.push(match[1]);
  }
  return values;
};
const tag = imageTagMode === 'full' ? revision : revision.slice(0, 7);
const namespace = 'hwlab-v02';
const selected = (selectedServices || '').split(',').filter(Boolean);
const serviceIds = selected.length ? selected : topLevelServiceIds(fs.readFileSync('deploy/deploy.yaml', 'utf8'));
const services = serviceIds.map((serviceId) => {
  const service = { serviceId, profile: 'v02', namespace, commitId: tag, sourceCommitId: revision, image: `${registryPrefix}/${serviceId}:${tag}`, imageTag: tag, digest: null, buildBackend: 'contract-skeleton' };
  return service;
});
fs.mkdirSync(path.dirname(catalogPath), { recursive: true });
fs.writeFileSync(catalogPath, JSON.stringify({ catalogVersion: 'v1', kind: 'hwlab-artifact-catalog', environment: 'v02', profile: 'v02', namespace, endpoint: "__HWLAB_V02_RUNTIME_ENDPOINT__", commitId: tag, artifactState: 'contract-skeleton', publish: { registryPrefix, sourceCommitId: revision, imageTag: tag, publishedAt: null }, allowedProfiles: ['v02'], forbiddenProfiles: ['dev', 'prod'], services }, null, 2) + '\n');
NODE
  echo '{"event":"gitops-artifact-catalog","phase":"prepare-source","status":"seeded-v02-skeleton"}'
fi
ci_timing_emit catalog-fetch succeeded "$catalog_fetch_started_ms"
echo 'node prepare-source complete; validation task count=__HWLAB_VALIDATION_TASK_COUNT__'
