#!/bin/bash
#
# Instalador do Tivra — https://cdn.tivrai.dev/install.sh
#
#   curl -fsSL https://cdn.tivrai.dev/install.sh | bash
#
# Variáveis opcionais:
#   TIVRA_HOME                 pasta de instalação (por omissão ~/.tivra)
#   TIVRA_INSTALL_YES=1        não pergunta nada (para scripts e CI)
#   TIVRA_INSTALL_NO_PATH=1    não toca nos ficheiros da shell
#   NO_COLOR=1                 sem cores
#
# Escrito para o bash 3.2 do macOS: sem arrays associativos, sem `mapfile`.
set -e

ORIGIN="https://cdn.tivrai.dev"
TIVRA_DIR="${TIVRA_HOME:-$HOME/.tivra}"
BIN_DIR="$TIVRA_DIR/bin"

# ------------------------------------------------------------------ aparência
# Tudo o que é interface vai para o stderr: o stdout fica limpo para quem encadeia.
if [ -t 2 ] && [ -z "${NO_COLOR:-}" ] && [ "${TERM:-dumb}" != "dumb" ]; then
    case "${COLORTERM:-}" in
        truecolor|24bit)
            GLOW=$'\033[38;2;165;180;252m'; OK=$'\033[38;2;48;209;88m'
            DIM=$'\033[38;2;138;138;138m'; ERR=$'\033[38;2;248;113;113m' ;;
        *)
            GLOW=$'\033[38;5;147m'; OK=$'\033[38;5;41m'
            DIM=$'\033[38;5;245m'; ERR=$'\033[38;5;210m' ;;
    esac
    BOLD=$'\033[1m'; RESET=$'\033[0m'
else
    GLOW=""; OK=""; DIM=""; ERR=""; BOLD=""; RESET=""
fi
if [ -t 2 ] && [ "${TERM:-dumb}" != "dumb" ]; then LIVE=1; else LIVE=0; fi

say()  { printf '%s\n' "$*" >&2; }
# Um passo concluído: losango, rótulo, valor. Os rótulos chegam já alinhados à mão: `%-13s`
# conta bytes ou caracteres conforme o locale, e "Versão" tem um acento.
step() { printf '  %s◆%s %s %s\n' "$OK" "$RESET" "$1" "$2" >&2; }
# N vezes o mesmo carácter. Feito com sed e não com um ciclo de concatenação: o bash 3.2
# do macOS corrompe caracteres multibyte em `x="$x━"` quando o locale é UTF-8.
repeat() { [ "$2" -gt 0 ] && printf '%*s' "$2" '' | sed "s/ /$1/g"; return 0; }
fail() {
    printf '\n  %s◆ %s%s\n' "$ERR" "$1" "$RESET" >&2
    [ -n "${2:-}" ] && printf '    %s%s%s\n' "$DIM" "$2" "$RESET" >&2
    printf '\n' >&2
    rm -f "${tmp:-}" "${errfile:-}"
    exit 1
}

# 1 234 567 bytes → "1,2" (MB, uma casa, vírgula decimal).
mb() { printf '%d,%d' $(( $1 / 1048576 )) $(( ($1 % 1048576) * 10 / 1048576 )); }

say ""
say "  ${GLOW}▎${RESET} ${BOLD}T I V R A${RESET}"
say "  ${GLOW}▎${RESET} ${DIM}O teu agente, no teu terminal.${RESET}"
say ""

# ------------------------------------------------------------------ sistema
case "$(uname -s)" in
    Darwin) os="macos"; os_label="macOS" ;;
    Linux)  os="linux"; os_label="Linux" ;;
    *)      fail "Sistema não suportado: $(uname -s)" "No Windows: irm $ORIGIN/install.ps1 | iex" ;;
esac
case "$(uname -m)" in
    x86_64|amd64)  arch="x86_64";  arch_label="x86-64" ;;
    arm64|aarch64) arch="aarch64"; arch_label="ARM64" ;;
    *)             fail "Arquitectura não suportada: $(uname -m)" ;;
esac
# Um terminal a correr em Rosetta diz x86_64 num Mac com Apple Silicon.
if [ "$os" = "macos" ] && [ "$arch" = "x86_64" ] && [ "$(sysctl -n hw.optional.arm64 2>/dev/null)" = "1" ]; then
    arch="aarch64"
fi
if [ "$os" = "macos" ]; then
    if [ "$arch" = "aarch64" ]; then arch_label="Apple Silicon"; else arch_label="Intel"; fi
fi
platform="${os}-${arch}"
step "Sistema     " "$os_label · $arch_label"

command -v curl >/dev/null 2>&1 || fail "Falta o curl." "Instala-o e volta a correr o instalador."

# ------------------------------------------------------------------ versão
# "version=…", "size=…", "sha256=…" — uma por linha. Sem resposta, instala-se na mesma,
# só sem percentagem nem verificação.
info="$(curl -fsSL --max-time 20 "$ORIGIN/dl/$platform.info" 2>/dev/null || true)"
field() { printf '%s\n' "$info" | sed -n "s/^$1=//p" | head -n 1; }
version="$(field version)"
size="$(field size)"
sha="$(field sha256)"
case "$size" in ''|*[!0-9]*) size=0 ;; esac

if [ -z "$version" ]; then
    # Distingue "esta plataforma ainda não tem binário" de "sem rede".
    code="$(curl -s -o /dev/null -w '%{http_code}' --max-time 20 "$ORIGIN/dl/$platform.info" 2>/dev/null || true)"
    [ "$code" = "404" ] && fail "Ainda não há Tivra para $os_label · $arch_label." "Plataformas disponíveis em $ORIGIN"
    [ "$code" = "000" ] && fail "Sem ligação a $ORIGIN." "Verifica a rede e tenta de novo."
fi

current=""
if [ -x "$BIN_DIR/tivra" ]; then
    current="$("$BIN_DIR/tivra" --version 2>/dev/null | awk '{print $2; exit}')"
fi
if [ -n "$current" ] && [ -n "$version" ] && [ "$current" != "$version" ]; then
    step "Versão      " "$version  ${DIM}(tens a $current)${RESET}"
elif [ -n "$current" ] && [ "$current" = "$version" ]; then
    step "Versão      " "$version  ${DIM}(a reinstalar)${RESET}"
else
    step "Versão      " "${version:-a mais recente}"
fi

# ------------------------------------------------------------------ descarregar
mkdir -p "$BIN_DIR"
tmp="$BIN_DIR/tivra.tmp.$$"
errfile="$BIN_DIR/tivra.err.$$"
trap 'rm -f "$tmp" "$errfile"' EXIT
trap 'printf "\n" >&2; exit 130' INT TERM

BAR_WIDTH=28
draw() {
    # $1 = bytes já no disco, $2 = segundos desde o início
    have=$1; secs=$2
    [ "$secs" -lt 1 ] && secs=1
    speed=$(( have / secs ))
    if [ "$size" -gt 0 ]; then
        pct=$(( have * 100 / size )); [ "$pct" -gt 100 ] && pct=100
        fill=$(( have * BAR_WIDTH / size )); [ "$fill" -gt "$BAR_WIDTH" ] && fill=$BAR_WIDTH
        bar="$(repeat '━' "$fill")"
        rest="$(repeat '─' $(( BAR_WIDTH - fill )))"
        printf '\r  %s◇%s %s%s%s%s%s  %3d%%  %s / %s MB  %s%s MB/s%s\033[K' \
            "$GLOW" "$RESET" "$GLOW" "$bar" "$DIM" "$rest" "$RESET" \
            "$pct" "$(mb "$have")" "$(mb "$size")" "$DIM" "$(mb "$speed")" "$RESET" >&2
    else
        printf '\r  %s◇%s A descarregar  %s MB  %s%s MB/s%s\033[K' \
            "$GLOW" "$RESET" "$(mb "$have")" "$DIM" "$(mb "$speed")" "$RESET" >&2
    fi
}

started=$(date +%s)
if [ "$LIVE" = "1" ]; then
    curl -fsSL "$ORIGIN/dl/$platform" -o "$tmp" 2>"$errfile" &
    pid=$!
    while kill -0 "$pid" 2>/dev/null; do
        have=0
        [ -f "$tmp" ] && have=$(wc -c < "$tmp" | tr -d ' ')
        draw "$have" $(( $(date +%s) - started ))
        sleep 0.2
    done
    if wait "$pid"; then dl_ok=1; else dl_ok=0; fi
    printf '\r\033[K' >&2
else
    say "  A descarregar o tivra ($platform)..."
    if curl -fsSL "$ORIGIN/dl/$platform" -o "$tmp" 2>"$errfile"; then dl_ok=1; else dl_ok=0; fi
fi

if [ "$dl_ok" != "1" ]; then
    reason="$(head -n 1 "$errfile" 2>/dev/null | sed 's/^curl: ([0-9]*) //')"
    fail "Não foi possível descarregar o Tivra para $platform." "${reason:-Verifica a rede e tenta de novo.}"
fi
got=$(wc -c < "$tmp" | tr -d ' ')
took=$(( $(date +%s) - started )); [ "$took" -lt 1 ] && took=1
step "Descarregado" "$(mb "$got") MB em ${took} s"

# ------------------------------------------------------------------ verificar
if [ -n "$sha" ]; then
    if command -v shasum >/dev/null 2>&1; then
        actual="$(shasum -a 256 "$tmp" | awk '{print $1}')"
    elif command -v sha256sum >/dev/null 2>&1; then
        actual="$(sha256sum "$tmp" | awk '{print $1}')"
    else
        actual=""
    fi
    if [ -n "$actual" ] && [ "$actual" != "$sha" ]; then
        fail "O ficheiro descarregado não confere com o publicado." "Esperado $sha, recebido $actual. Nada foi instalado."
    fi
fi
chmod +x "$tmp"
if ! "$tmp" --version >/dev/null 2>&1; then
    fail "O binário descarregado não corre nesta máquina." "Nada foi instalado."
fi
if [ -n "$sha" ] && [ -n "${actual:-}" ]; then
    step "Verificado  " "SHA-256 confere"
else
    step "Verificado  " "o binário corre"
fi

mv -f "$tmp" "$BIN_DIR/tivra"
step "Instalado   " "$(printf '%s' "$BIN_DIR/tivra" | sed "s|^$HOME|~|")"

# ------------------------------------------------------------------ PATH
path_note=""
case ":$PATH:${TIVRA_INSTALL_NO_PATH:+$BIN_DIR:}" in
    *":$BIN_DIR:"*) ;;
    *)
        shell_name="$(basename "${SHELL:-bash}")"
        case "$shell_name" in
            zsh)  shell_rc="$HOME/.zshrc" ;;
            bash) if [ "$os" = "macos" ]; then shell_rc="$HOME/.bash_profile"; else shell_rc="$HOME/.bashrc"; fi ;;
            fish) shell_rc="" ;;
            *)    shell_rc="$HOME/.profile" ;;
        esac
        if [ -n "$shell_rc" ]; then
            # Escreve-se com $HOME por extenso, como as instalações anteriores, e não se
            # repete a linha se já lá estiver numa das duas formas.
            portable="$(printf '%s' "$BIN_DIR" | sed "s|^$HOME|\$HOME|")"
            if ! grep -qsF -e "$BIN_DIR" -e "$portable" "$shell_rc"; then
                printf '\n# Tivra\nexport PATH="%s:$PATH"\n' "$portable" >> "$shell_rc"
            fi
            path_note="Abre um terminal novo (ou corre: source $(printf '%s' "$shell_rc" | sed "s|^$HOME|~|")) para o comando ${BOLD}tivra${RESET} ficar disponível."
        else
            path_note="Junta $BIN_DIR ao PATH da tua shell para usares o comando ${BOLD}tivra${RESET}."
        fi
        ;;
esac

# ------------------------------------------------------------------ a seguir
say ""
say "  ${BOLD}Pronto.${RESET} ${DIM}Próximos passos:${RESET}"
say ""
say "    ${GLOW}›${RESET} ${BOLD}tivra login${RESET}   ${DIM}inicia sessão com a tua conta${RESET}"
say "    ${GLOW}›${RESET} ${BOLD}tivra link${RESET}    ${DIM}liga esta máquina à app — app.tivrai.dev${RESET}"
say "    ${GLOW}›${RESET} ${BOLD}tivra${RESET}         ${DIM}abre o agente nesta pasta${RESET}"
say ""
[ -n "$path_note" ] && { say "  ${DIM}$path_note${RESET}"; say ""; }

# Com alguém ao teclado e sem sessão guardada, oferece o passo seguinte. O script chega
# pelo stdin (curl | bash), por isso a resposta lê-se do terminal.
if [ -z "${TIVRA_INSTALL_YES:-}" ] && [ "$LIVE" = "1" ] && [ ! -f "$TIVRA_DIR/auth.json" ] && (exec < /dev/tty) 2>/dev/null; then
    printf '  Iniciar sessão agora? %s[S/n]%s ' "$DIM" "$RESET" >&2
    answer=""
    read -r answer < /dev/tty || answer="n"
    case "$answer" in
        ""|s|S|sim|Sim|y|Y)
            say ""
            "$BIN_DIR/tivra" login < /dev/tty || say "  ${DIM}Podes iniciar sessão mais tarde com: tivra login${RESET}"
            ;;
        *) say "" ;;
    esac
fi
