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

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=_config.sh
source "${SCRIPT_DIR}/_config.sh"

log() { printf '[provision] %s\n' "$*"; }
die() { printf '[provision][error] %s\n' "$*" >&2; exit 1; }

# --- Prerequisites ---

command -v hetzner-k3s >/dev/null 2>&1 || die "Missing: hetzner-k3s CLI. Install: https://github.com/vitobotta/hetzner-k3s"
command -v kubectl >/dev/null 2>&1 || die "Missing: kubectl"

HCLOUD_TOKEN="$(cfg_require cluster.hcloud_token "Hetzner API token")"
export HCLOUD_TOKEN

# Validate SSH keys
SSH_PUB="$(cfg cluster.ssh_public_key | sed "s|~|${HOME}|g")"
SSH_PRIV="$(cfg cluster.ssh_private_key | sed "s|~|${HOME}|g")"
[[ -f "${SSH_PUB}" ]] || die "SSH public key not found: ${SSH_PUB}"
[[ -f "${SSH_PRIV}" ]] || die "SSH private key not found: ${SSH_PRIV}"

# --- Generate hetzner-k3s cluster config from config.yaml ---

CLUSTER_CONFIG="${DEPLOY_DIR}/cluster-config.yaml"
log "Generating cluster-config.yaml from config.yaml..."
generate_cluster_config > "${CLUSTER_CONFIG}"

# --- Provision ---

INSTANCE_TYPE="$(cfg cluster.instance_type)"
LOCATION="$(cfg cluster.location)"
NODE_COUNT="$(node_count)"

log "Provisioning K3s cluster on Hetzner Cloud..."
log "  Nodes: ${NODE_COUNT}x ${INSTANCE_TYPE} in ${LOCATION}"
log "  This takes about 5-10 minutes."
echo ""

hetzner-k3s create --config "${CLUSTER_CONFIG}"

KUBECONFIG_PATH="${DEPLOY_DIR}/kubeconfig"

if [[ ! -f "${KUBECONFIG_PATH}" ]]; then
  die "Provisioning completed but kubeconfig not found. Check hetzner-k3s output."
fi

# --- Write node IPs back to config.yaml ---

log "Querying node IPs..."
export KUBECONFIG="${KUBECONFIG_PATH}"

python3 -c "
import yaml, subprocess, json

# Get node info from kubectl
result = subprocess.run(
    ['kubectl', 'get', 'nodes', '-o', 'json'],
    capture_output=True, text=True
)
nodes_json = json.loads(result.stdout)

# Build name → IP map
ip_map = {}
for node in nodes_json.get('items', []):
    name = node['metadata']['name']
    for addr in node.get('status', {}).get('addresses', []):
        if addr['type'] == 'ExternalIP':
            ip_map[name] = addr['address']
            break
    else:
        for addr in node.get('status', {}).get('addresses', []):
            if addr['type'] == 'InternalIP':
                ip_map[name] = addr['address']
                break

# Update config.yaml with IPs
with open('${CONFIG_FILE}') as f:
    config = yaml.safe_load(f)

updated = 0
for i, node in enumerate(config.get('nodes', [])):
    for real_name, ip in ip_map.items():
        if node['name'] in real_name or real_name in node['name']:
            config['nodes'][i]['ip'] = ip
            config['nodes'][i]['name'] = real_name
            updated += 1
            break

if updated == 0 and ip_map:
    # Names didn't match — assign by index
    for i, (name, ip) in enumerate(sorted(ip_map.items())):
        if i < len(config['nodes']):
            config['nodes'][i]['name'] = name
            config['nodes'][i]['ip'] = ip
            updated += 1

with open('${CONFIG_FILE}', 'w') as f:
    yaml.dump(config, f, default_flow_style=False, sort_keys=False)

print(f'Updated {updated} node IPs in config.yaml')
for name, ip in sorted(ip_map.items()):
    print(f'  {name}: {ip}')
"

# --- Label Redis node ---

REDIS_NODE="$(nodes_with_role redis | head -1)"
if [[ -n "${REDIS_NODE}" ]]; then
  # Find the actual K8s node name that matches
  ACTUAL_NODE="$(kubectl get nodes -o jsonpath='{.items[*].metadata.name}' | tr ' ' '\n' | head -1)"
  log "Labeling node ${ACTUAL_NODE} for Redis..."
  kubectl label node "${ACTUAL_NODE}" honeydue/redis=true --overwrite
fi

log ""
log "Cluster provisioned successfully."
log ""
log "Next steps:"
log "  export KUBECONFIG=${KUBECONFIG_PATH}"
log "  kubectl get nodes"
log "  ./scripts/02-setup-secrets.sh"
