#!/usr/bin/env bash
#
# tools/dev-env.sh — bootstrap DETERMINÍSTICO do `.env` para desenvolvimento.
#
# O que faz (idempotente, nunca sobrescreve o que o dono decidiu):
#   1. cria o `.env` a partir do `.env.example` quando ele não existe;
#   2. resolve a **porta publicada** (`WEB_PORT`) de forma determinística por instância:
#      sem `WEB_PORT` no `.env`, deriva `507x` do nome do projeto — a mesma cópia
#      sempre sobe na mesma porta, e cópias/branches diferentes não colidem;
#   3. mantém `APP_URL` coerente com a porta publicada (só para hosts locais;
#      `https://example.gov.br` de produção nunca é tocado);
#   4. `--instance` isola a stack: `COMPOSE_PROJECT_NAME=<slug>-<hash8 do caminho>`
#      (containers/redes/**volumes** próprios — dois clones não compartilham banco);
#   5. `--runtime=docker|podman` grava a escolha (`CONTAINER_RUNTIME`) e o sufixo de
#      SELinux dos bind mounts (`MOUNT_LABEL`) que o `docker-compose.yml` interpola —
#      **docker é o padrão**; podman é opt-in de dev (ADR-045).
#
# Uso:
#   tools/dev-env.sh                    # garante porta/APP_URL (chamado pelo `make up`)
#   tools/dev-env.sh --instance         # stack paralela (branch/cópia) com volumes próprios
#                                       # (use cópias separadas do repo: os stamps de `make check`
#                                       #  são por checkout; no mesmo diretório, CHECK_FORCE_PREP=1)
#   tools/dev-env.sh --runtime=podman   # opt-in de dev: CONTAINER_RUNTIME=podman + MOUNT_LABEL=
#   tools/dev-env.sh --print            # mostra o que está resolvido (sem escrever)
#
# Determinismo (ADR-001): nada de porta "livre no momento"; a porta é função do nome do
# projeto (cksum), então um novo `make up` reusa exatamente a mesma.
set -Eeuo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"

INSTANCE=0
PRINT=0
RUNTIME=""
DECLARED=()

usage() {
    sed -n '2,25p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
}

while [ $# -gt 0 ]; do
    case "$1" in
        --instance) INSTANCE=1 ;;
        --print) PRINT=1 ;;
        --runtime=*) RUNTIME="${1#*=}" ;;
        --runtime) shift; RUNTIME="${1:-}" ;;
        -h | --help) usage; exit 0 ;;
        *) echo "dev-env: flag desconhecida: $1" >&2; usage >&2; exit 2 ;;
    esac
    shift
done

case "$RUNTIME" in
    '' | docker | podman) : ;;
    *) echo "dev-env: runtime inválido '$RUNTIME' (use docker ou podman)." >&2; exit 2 ;;
esac

# Sem `.env` não há compose (ele é a fonte única de portas/segredos). `--print` só lê.
if [ ! -f .env ]; then
    if [ "$PRINT" = 1 ]; then
        echo "dev-env: '.env' ausente (rode 'make env')." >&2
        exit 1
    fi
    if [ ! -f .env.example ]; then
        echo "dev-env: '.env' e '.env.example' ausentes." >&2
        exit 1
    fi
    cp .env.example .env
    echo "dev-env: .env criado a partir de .env.example (revise os segredos)."
fi

env_value() {
    local key="$1"
    grep -E "^${key}=" .env | head -1 | cut -d= -f2- \
        | sed -E 's/^"(.*)"$/\1/; s/^'"'"'(.*)'"'"'$/\1/' || true
}

CHANGED=()
set_var() {
    local key="$1" value="$2"
    if grep -qE "^${key}=" .env; then
        [ "$(env_value "$key")" = "$value" ] && return 0
        sed -i -E "s|^${key}=.*|${key}=${value}|" .env
    else
        printf '%s=%s\n' "$key" "$value" >> .env
    fi
    CHANGED+=("${key}=${value}")
}

unset_var() {
    local key="$1"
    grep -qE "^${key}=" .env || return 0
    sed -i -E "/^${key}=/d" .env
    CHANGED+=("${key} (removido)")
}

# ── 1. runtime de containers ───────────────────────────────────────────────────────
# `CONTAINER_RUNTIME` é lido por `tools/runtime.sh`. `MOUNT_LABEL` vazio no podman desliga o
# `:Z` do bind mount (lá o container usa `label=disable`; ver docker-compose.podman.yml).
if [ "$RUNTIME" = "podman" ]; then
    set_var CONTAINER_RUNTIME podman
    set_var MOUNT_LABEL ""
elif [ "$RUNTIME" = "docker" ]; then
    set_var CONTAINER_RUNTIME docker
    unset_var MOUNT_LABEL
fi

# ── 2. identidade da instância (opt-in) ────────────────────────────────────────────
INSTANCE_HASH="$(printf '%s' "$(pwd -P)" | sha1sum | cut -c1-8)"
BASE_NAME="$(env_value COMPOSE_PROJECT_NAME)"
[ -n "$BASE_NAME" ] || BASE_NAME="$(COMPOSE_PROJECT_NAME= bash "$ROOT/tools/project-name.sh")"

if [ "$INSTANCE" = 1 ]; then
    case "$BASE_NAME" in
        *-"$INSTANCE_HASH") NAME="$BASE_NAME" ;;
        *) NAME="${BASE_NAME}-${INSTANCE_HASH}" ;;
    esac
    set_var COMPOSE_PROJECT_NAME "$NAME"
else
    NAME="$BASE_NAME"
fi

# ── 3. porta publicada determinística (faixa fixa 507xx) ───────────────────────────
# O dono reservou **507xx** para portas publicadas no host (regra do projeto). 50790–50799
# ficam para os profiles dev-only (mailpit/jaeger); a porta do app deriva em 50700–50789,
# sempre a mesma para a mesma instância.
port_for() { printf '%s' "$((50700 + $(printf '%s' "$1" | cksum | cut -d' ' -f1) % 90))"; }
in_range() { case "$1" in 507[0-8][0-9]) return 0 ;; *) return 1 ;; esac; }

PORT="$(env_value WEB_PORT)"
PORT_ENV="${WEB_PORT:-}"

if [ -n "$PORT_ENV" ]; then
    # Porta explícita (`WEB_PORT=50710 make env`): é do dono, mas a faixa é contrato.
    in_range "$PORT_ENV" || { echo "dev-env: WEB_PORT=${PORT_ENV} fora da faixa 507xx (50700–50789)." >&2; exit 2; }
    PORT="$PORT_ENV"
elif [ "$INSTANCE" = 1 ]; then
    # Stack paralela: a porta acompanha o nome da instância (isolar sem colidir é o ponto).
    PORT="$(port_for "$NAME")"
elif [ -z "$PORT" ] || ! in_range "$PORT" || [ "$PORT" = "$(port_for "$BASE_NAME")" ]; then
    # Sem porta, fora da faixa (ex.: `.env` antigo com 8090) ou derivada de um nome anterior.
    PORT="$(port_for "$NAME")"
fi
set_var WEB_PORT "$PORT"

# ── 4. APP_URL coerente com a porta (somente host local) ───────────────────────────
APP_URL="$(env_value APP_URL)"
URL_HOST="$(printf '%s' "$APP_URL" | sed -nE 's#^[a-z]+://([^/:]+).*#\1#p')"
if [ -z "$APP_URL" ] || [ "$URL_HOST" = "localhost" ] || [ "$URL_HOST" = "127.0.0.1" ]; then
    APP_URL="http://localhost:${PORT}"
    set_var APP_URL "$APP_URL"
fi

# ── 5. saída ───────────────────────────────────────────────────────────────────────
DATA_PATH="$(env_value DATA_PATH)"; DATA_PATH="${DATA_PATH:-./s3-local}"
STORAGE_PATH="$(env_value STORAGE_PATH)"; STORAGE_PATH="${STORAGE_PATH:-./storage}"
RUNTIME_V="$(env_value CONTAINER_RUNTIME)"; RUNTIME_V="${RUNTIME_V:-docker}"

if [ "$PRINT" = 1 ]; then
    printf 'runtime:  %s\n' "$RUNTIME_V"
    printf 'project:  %s\n' "$(bash "$ROOT/tools/project-name.sh")"
    printf 'port:     %s\n' "$PORT"
    printf 'url:      %s\n' "$APP_URL"
    printf 'data:     %s\n' "$DATA_PATH"
    printf 'storage:  %s\n' "$STORAGE_PATH"
    exit 0
fi

if [ "${#CHANGED[@]}" -gt 0 ]; then
    printf 'dev-env: %s\n' "$(printf '%s · ' "${CHANGED[@]}" | sed 's/ · $//')"
fi
printf 'dev-env: %s · porta %s · %s\n' "$NAME" "$PORT" "$APP_URL"
