#!/usr/bin/env bash
set -euo pipefail

HVIGOR_BIN="${HVIGOR:-hvigorw}"
MODULE_NAME="{{HARMONY_MODULE_NAME}}"
BUILD_PROFILE="build-profile.json5"
BACKUP_DIR=".biucing/release"
BACKUP_PROFILE="${BACKUP_DIR}/build-profile.json5.backup"
GENERATED_PROFILE="${BACKUP_DIR}/build-profile.json5.generated"
RESTORE_PROFILE="${BACKUP_DIR}/build-profile.json5.restore"
BUILD_MARKER="${BACKUP_DIR}/release-build.started"

if [[ ! -f "local.properties" ]]; then
  cat >&2 <<'EOF'
local.properties is missing.

Copy docs/release-signing.local.properties.example to local.properties and fill in
your HarmonyOS signing material before running make release.
EOF
  exit 1
fi

./scripts/verify-supply-chain
./scripts/release-preflight

if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1 || \
  ! git ls-files --error-unmatch "$BUILD_PROFILE" >/dev/null 2>&1; then
  echo "$BUILD_PROFILE must be tracked in a Git repository before a signed release." >&2
  exit 1
fi

if ! git diff --quiet -- "$BUILD_PROFILE" || ! git diff --cached --quiet -- "$BUILD_PROFILE"; then
  echo "$BUILD_PROFILE has staged or unstaged changes." >&2
  echo "Commit or stash those changes before running a signed release." >&2
  exit 1
fi

if ORIGINAL_MODE="$(stat -f '%Lp' "$BUILD_PROFILE" 2>/dev/null)"; then
  :
else
  ORIGINAL_MODE="$(stat -c '%a' "$BUILD_PROFILE")"
fi

umask 077
mkdir -p "$BACKUP_DIR"
cp -p "$BUILD_PROFILE" "$BACKUP_PROFILE"
chmod 600 "$BACKUP_PROFILE"

restore_build_profile() {
  local original_status=$?
  local restore_status=0

  trap - EXIT HUP INT TERM
  rm -f "$GENERATED_PROFILE" "$RESTORE_PROFILE" "$BUILD_MARKER"

  if [[ -f "$BACKUP_PROFILE" ]]; then
    if cp -p "$BACKUP_PROFILE" "$RESTORE_PROFILE" && \
      mv -f "$RESTORE_PROFILE" "$BUILD_PROFILE" && chmod "$ORIGINAL_MODE" "$BUILD_PROFILE"; then
      if cmp -s "$BACKUP_PROFILE" "$BUILD_PROFILE"; then
        rm -f "$BACKUP_PROFILE"
        rmdir "$BACKUP_DIR" 2>/dev/null || true
      else
        echo "Failed to verify restoration of $BUILD_PROFILE; backup retained at $BACKUP_PROFILE." >&2
        restore_status=1
      fi
    else
      echo "Failed to restore $BUILD_PROFILE; backup retained at $BACKUP_PROFILE." >&2
      restore_status=1
    fi
  fi

  if [[ "$restore_status" -ne 0 ]]; then
    exit "$restore_status"
  fi
  exit "$original_status"
}
trap restore_build_profile EXIT
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM

BUILD_PROFILE_PATH="$BUILD_PROFILE" GENERATED_PROFILE_PATH="$GENERATED_PROFILE" node <<'NODE'
const fs = require('fs');
const path = require('path');

const localPropertiesPath = 'local.properties';
const buildProfilePath = process.env.BUILD_PROFILE_PATH;
const generatedProfilePath = process.env.GENERATED_PROFILE_PATH;
const requiredKeys = [
  'biucing.harmony.signing.certpath',
  'biucing.harmony.signing.profile',
  'biucing.harmony.signing.storeFile',
  'biucing.harmony.signing.storePassword',
  'biucing.harmony.signing.keyAlias',
  'biucing.harmony.signing.keyPassword'
];

function parseProperties(raw) {
  const values = {};
  for (const line of raw.split(/\r?\n/)) {
    const trimmed = line.trim();
    if (!trimmed || trimmed.startsWith('#')) {
      continue;
    }
    const separator = trimmed.indexOf('=');
    if (separator < 0) {
      continue;
    }
    const key = trimmed.slice(0, separator).trim();
    const value = trimmed.slice(separator + 1).trim();
    values[key] = value;
  }
  return values;
}

const properties = parseProperties(fs.readFileSync(localPropertiesPath, 'utf8'));
const missing = requiredKeys.filter((key) => !properties[key]);
if (missing.length > 0) {
  console.error(`Missing signing key(s) in ${localPropertiesPath}:`);
  for (const key of missing) {
    console.error(`  - ${key}`);
  }
  process.exit(1);
}

for (const key of [
  'biucing.harmony.signing.certpath',
  'biucing.harmony.signing.profile',
  'biucing.harmony.signing.storeFile'
]) {
  const value = properties[key];
  const resolved = path.isAbsolute(value) ? value : path.resolve(value);
  if (!fs.existsSync(resolved)) {
    console.error(`Signing file for ${key} does not exist: ${value}`);
    process.exit(1);
  }
}

const buildProfile = JSON.parse(fs.readFileSync(buildProfilePath, 'utf8'));
const material = {
  certpath: properties['biucing.harmony.signing.certpath'],
  profile: properties['biucing.harmony.signing.profile'],
  storeFile: properties['biucing.harmony.signing.storeFile'],
  storePassword: properties['biucing.harmony.signing.storePassword'],
  keyAlias: properties['biucing.harmony.signing.keyAlias'],
  keyPassword: properties['biucing.harmony.signing.keyPassword'],
  signAlg: properties['biucing.harmony.signing.signAlg'] || 'SHA256withECDSA'
};

buildProfile.app.signingConfigs = [
  {
    name: 'release',
    type: 'HarmonyOS',
    material
  }
];
for (const product of buildProfile.app.products || []) {
  product.signingConfig = 'release';
}

fs.writeFileSync(generatedProfilePath, `${JSON.stringify(buildProfile, null, 2)}\n`, { mode: 0o600 });
console.log('Injected release signing config from local.properties.');
NODE

mv -f "$GENERATED_PROFILE" "$BUILD_PROFILE"

touch "$BUILD_MARKER"
"$HVIGOR_BIN" assembleHap --mode module -p "module=${MODULE_NAME}" -p buildMode=release
release_artifact="$(MODULE_BUILD_ROOT="${MODULE_NAME}/build" BUILD_MARKER_PATH="$BUILD_MARKER" node <<'NODE'
const fs = require('fs');
const path = require('path');
const markerTime = fs.statSync(process.env.BUILD_MARKER_PATH).mtimeMs;
const candidates = [];

function visit(directory) {
  if (!fs.existsSync(directory)) return;
  for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
    const candidate = path.join(directory, entry.name);
    if (entry.isDirectory()) {
      visit(candidate);
    } else if (entry.isFile() && candidate.endsWith('.hap')) {
      const modified = fs.statSync(candidate).mtimeMs;
      if (modified > markerTime) candidates.push({ candidate, modified });
    }
  }
}

visit(process.env.MODULE_BUILD_ROOT);
candidates.sort((left, right) => right.modified - left.modified);
if (candidates.length > 0) process.stdout.write(candidates[0].candidate);
NODE
)"
if [[ -z "$release_artifact" ]]; then
  echo "Release build did not produce a new HAP artifact." >&2
  exit 1
fi
./scripts/verify-release-artifact "$release_artifact"

echo "Release build finished. Restoring build-profile.json5."
