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

usage() {
  cat <<'USAGE'
Usage:
  scripts/init-template \
    --repo-name my-app

Optional:
  --dry-run
  --repo-url https://git.olb42.com/olb42/my-app.git
  --namespace my-app
  --release-name my-app
  --hostname my-app.example.com
USAGE
}

die() {
  echo "Error: $*" >&2
  exit 1
}

add_error() {
  errors+=("$*")
}

add_warning() {
  warnings+=("$*")
}

validate_dns_label() {
  local value="$1"
  [[ ${#value} -le 63 && "$value" =~ ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ ]]
}

validate_hostname() {
  local value="$1"
  [[ ${#value} -le 253 && "$value" != .* && "$value" != *. ]] || return 1

  local old_ifs="$IFS"
  local labels=()
  IFS='.'
  read -r -a labels <<< "$value"
  IFS="$old_ifs"

  local label
  for label in "${labels[@]}"; do
    validate_dns_label "$label" || return 1
  done
}

print_preflight() {
  local status="$1"

  echo "Preflight checks for $repo_name"
  echo "  template:  $template_dir_real"
  echo "  target:    $target_dir"
  echo "  repo URL:  $repo_url"
  echo "  namespace: $namespace"
  echo "  hostname:  $hostname"
  echo

  if [[ ${#warnings[@]} -gt 0 ]]; then
    echo "Warnings:"
    local warning
    for warning in "${warnings[@]}"; do
      echo "  - $warning"
    done
    echo
  fi

  if [[ ${#errors[@]} -gt 0 ]]; then
    echo "Failures:"
    local error
    for error in "${errors[@]}"; do
      echo "  - $error"
    done
    echo
    echo "$status"
    return 1
  fi

  echo "$status"
}

run_preflight() {
  local include_remote_check="${1:-false}"
  errors=()
  warnings=()

  command -v git >/dev/null 2>&1 || add_error "git is required"
  command -v python3 >/dev/null 2>&1 || add_error "python3 is required"
  command -v cp >/dev/null 2>&1 || add_error "cp is required"

  if [[ -z "$repo_name" ]]; then
    add_error "--repo-name is required"
  elif [[ ! "$repo_name" =~ ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ ]]; then
    add_error "--repo-name must be kebab-case using lowercase letters, numbers, and hyphens"
  fi

  if [[ -z "$template_dir_real" ]]; then
    add_error "template directory not found: $template_dir"
  elif [[ "$current_dir/" != "$template_dir_real"/* ]]; then
    add_error "run this script from $template_dir or one of its subdirectories"
  elif [[ ! -d "$template_dir_real/.git" ]]; then
    add_error "template directory is not a git repository: $template_dir_real"
  else
    local branch
    branch="$(git -C "$template_dir_real" branch --show-current 2>/dev/null || true)"
    [[ "$branch" == "init" ]] || add_warning "template branch is '$branch', expected 'init'"
  fi

  if [[ -d "$apps_dir" ]]; then
    [[ -w "$apps_dir" ]] || add_error "apps directory is not writable: $apps_dir"
  else
    local apps_parent
    apps_parent="$(dirname "$apps_dir")"
    [[ -d "$apps_parent" && -w "$apps_parent" ]] || add_error "cannot create apps directory under: $apps_parent"
  fi
  [[ -e "$target_dir" ]] && add_error "target directory already exists: $target_dir"

  validate_dns_label "$namespace" || add_error "--namespace must be a valid Kubernetes DNS label"
  validate_dns_label "$release_name" || add_error "--release-name must be a valid Helm release name"
  validate_hostname "$hostname" || add_error "--hostname must be a valid DNS hostname"
  [[ "$repo_url" == *$'\n'* || "$repo_url" == *$'\r'* ]] && add_error "--repo-url must not contain newlines"
  [[ "$repo_url" =~ ^https://git\.olb42\.com/olb42/[a-z0-9]([-a-z0-9]*[a-z0-9])?\.git$ ]] || add_error "--repo-url must match https://git.olb42.com/olb42/<kebab-repo>.git"
  [[ "$repo_url" == "https://git.olb42.com/olb42/$repo_name.git" ]] || add_warning "--repo-url does not match --repo-name"

  if [[ "$include_remote_check" == true && ${#errors[@]} -eq 0 ]]; then
    local remote_output
    remote_output="$(GIT_TERMINAL_PROMPT=0 git ls-remote --heads "$repo_url" main init 2>&1 || true)"
    if printf '%s\n' "$remote_output" | grep -q 'refs/heads/'; then
      add_error "remote already has main/init branches at $repo_url"
    else
      local remote_check_output
      remote_check_output="$(GIT_TERMINAL_PROMPT=0 git ls-remote "$repo_url" 2>&1 || true)"
      if printf '%s\n' "$remote_check_output" | grep -qi '^fatal:'; then
        add_error "remote repository is not reachable without prompting: $repo_url ($remote_check_output)"
      fi
    fi
  fi
}

repo_name=""
repo_url=""
namespace=""
release_name=""
hostname=""
dry_run=false
errors=()
warnings=()

while [[ $# -gt 0 ]]; do
  case "$1" in
    --repo-name) [[ $# -ge 2 ]] || die "--repo-name requires a value"; repo_name="$2"; shift 2 ;;
    --repo-url) [[ $# -ge 2 ]] || die "--repo-url requires a value"; repo_url="$2"; shift 2 ;;
    --namespace) [[ $# -ge 2 ]] || die "--namespace requires a value"; namespace="$2"; shift 2 ;;
    --release-name) [[ $# -ge 2 ]] || die "--release-name requires a value"; release_name="$2"; shift 2 ;;
    --hostname) [[ $# -ge 2 ]] || die "--hostname requires a value"; hostname="$2"; shift 2 ;;
    --dry-run) dry_run=true; shift ;;
    -h|--help) usage; exit 0 ;;
    *) echo "Unknown argument: $1"; usage; exit 1 ;;
  esac
done

template_dir="$HOME/devops/infra/templates/template"
apps_dir="$HOME/devops/apps"
target_dir="$apps_dir/$repo_name"

current_dir="$(pwd -P)"
template_dir_real="$(cd "$template_dir" 2>/dev/null && pwd -P || true)"

repo_url="${repo_url:-https://git.olb42.com/olb42/$repo_name.git}"
release_name="${release_name:-$repo_name}"
hostname="${hostname:-$repo_name.olb42.com}"
namespace="${namespace:-$repo_name}"

run_preflight "$dry_run"

if [[ "$dry_run" == true ]]; then
  if [[ ${#errors[@]} -gt 0 ]]; then
    print_preflight "Dry run failed. No files were copied."
    exit 1
  fi
  print_preflight "Dry run passed. No files were copied."
  exit 0
fi

if [[ ${#errors[@]} -gt 0 ]]; then
  usage
  print_preflight "Template initialization failed before copying files." >&2
  exit 1
fi

mkdir -p "$apps_dir"
cp -a "$template_dir_real" "$target_dir"

cd "$target_dir"

git reset --mixed >/dev/null

python3 - "$repo_name" "$repo_url" "$namespace" "$release_name" "$hostname" <<'PY'
from pathlib import Path
import sys

repo_name, repo_url, namespace, release_name, hostname = sys.argv[1:]
replacements = {
    "${REPO_NAME_KEBAB}": repo_name,
    "${REPO_HTTPS_URL}": repo_url,
    "${APP_NAMESPACE}": namespace,
    "${HELM_RELEASE_NAME}": release_name,
    "${APP_HOSTNAME}": hostname,
}

for path in Path(".").rglob("*"):
    if not path.is_file():
        continue
    if ".git" in path.parts or path.name == "init-template":
        continue
    try:
        text = path.read_text()
    except UnicodeDecodeError:
        continue
    original = text
    for old, new in replacements.items():
        text = text.replace(old, new)
    if text != original:
        path.write_text(text)
PY

git branch -M main
while IFS= read -r remote; do
  git remote remove "$remote"
done < <(git remote)
git remote add origin "$repo_url"

echo "Template initialized for $repo_name"
echo "Created $target_dir"
echo "Remote origin: $repo_url"
echo "Next: review manifest/overlays/production and push main"
