#!/usr/bin/env bash
set -euo pipefail
# POS: docker compose — Docker Compose service manager (ls/up/down/restart/logs/update/config)
# POS_SUBCMDS: ls installed up down restart logs update config
# POS_CONFIG: compose | compose.env | TS_AUTHKEY=secret:Tailscale auth key for the sidecar | TZ=:Service timezone (default Europe/Amsterdam) | DNS_SERVER=:Custom DNS server (default 9.9.9.9) | SERVICES_BASE=:Deployment root (default /srv)
source "$(dirname "$0")/../lib/common.sh" 2>/dev/null || source "$(dirname "$0")/common.sh"

SCALE_DIR="${SCALE_DIR:-/usr/local/share/linux_post_install/scale-tail/services}"
CONFIG_ENV="${CONFIG_ENV:-${HOME}/.config/linux_post_install/compose.env}"

usage() {
    cat <<EOF
Usage: pos docker compose <command> [args]

Commands:
  ls                          List all available ScaleTail service templates
  installed                   List services already deployed on this machine
  up       <service>          Deploy or start a service
  down     <service>          Stop and remove a deployed service
  restart  <service>          Restart a running service
  logs     <service> [-f]     View logs (use -f to follow)
  update                      Pull latest ScaleTail templates + refresh all deployed compose files
  config                      Show current global configuration
  config set KEY=VALUE        Set a global default (e.g. TS_AUTHKEY, TZ, SERVICES_BASE)
  config edit                 Open global config in your editor (\$EDITOR)

─── Config Strategy ──────────────────────────────────────────

  Three layers — each overrides the one above:

  1. Template defaults
     /usr/local/share/linux_post_install/scale-tail/services/<name>/.env

  2. Global config (your defaults — set once, applies to all services)
     ~/.config/linux_post_install/compose.env
     Keys: TS_AUTHKEY | TZ | DNS_SERVER | SERVICES_BASE

  3. Per-service config (created on first deploy, preserved forever)
     /srv/<service>/.env       (or \$SERVICES_BASE/<service>/.env)

  On first "up", the service .env is generated from the template
  and filled with values from your global config. After that, the
  per-service .env is never overwritten — even by "update".

─── Paths ────────────────────────────────────────────────────

  Templates:    /usr/local/share/linux_post_install/scale-tail/services/
  Deployments:  \$SERVICES_BASE/<service>/   (default: /srv/<service>/)
  Global conf:  ~/.config/linux_post_install/compose.env

─── Quick Start ──────────────────────────────────────────────

  1. Set your Tailscale auth key (required):
     pos docker compose config set TS_AUTHKEY=tskey-auth-xxxxx

  2. Deploy a service:
     pos docker compose up jellyfin

  3. Open https://jellyfin.tail-xxxxx.ts.net

Examples:
  pos docker compose up jellyfin
  pos docker compose down actual-budget
  pos docker compose logs home-assistant -f
  pos docker compose config set TZ=Asia/Tokyo
  pos docker compose config set SERVICES_BASE=/data
EOF
    exit 0
}

check_deps() {
    command -v docker &>/dev/null || err "docker not found — install with: sudo apt install docker.io"
}

check_templates() {
    [ -d "$SCALE_DIR" ] || err "ScaleTail templates not found at $SCALE_DIR — run 'install.sh' to set them up"
}

check_service() {
    local svc="$1"
    [ -d "$SCALE_DIR/$svc" ] || err "Unknown service '$svc' — run 'pos docker compose ls' to see available services"
}

load_global_config() {
    mkdir -p "$(dirname "$CONFIG_ENV")"
    [ -f "$CONFIG_ENV" ] && source "$CONFIG_ENV"
    SERVICES_BASE="${SERVICES_BASE:-/srv}"
}

service_dir() {
    local svc="$1"
    echo "$SERVICES_BASE/$svc"
}

###############################################################################
# Commands
###############################################################################

cmd_ls() {
    check_templates
    local names=()
    for svc in "$SCALE_DIR"/*/; do
        names+=("$(basename "$svc")")
    done
    IFS=$'\n' names=($(sort <<<"${names[*]}")); unset IFS

    echo "${CYAN}Available ScaleTail services:${RESET}"
    echo "${CYAN}────────────────────────────────────────${RESET}"
    local name
    for name in "${names[@]}"; do
        printf "  ${GREEN}%s${RESET}\n" "$name"
    done
    echo "${CYAN}────────────────────────────────────────${RESET}"
    echo "  ${#names[@]} services total"
}

cmd_installed() {
    load_global_config
    local count=0

    echo "${CYAN}Deployed services:${RESET}"
    echo "${CYAN}────────────────────────────────────────${RESET}"

    [ -d "$SERVICES_BASE" ] || { echo "  (none — $SERVICES_BASE does not exist)"; echo "${CYAN}────────────────────────────────────────${RESET}"; echo "  0 services deployed"; return; }

    for svc in "$SERVICES_BASE"/*/; do
        [ -d "$svc" ] || continue
        local name
        name=$(basename "$svc")
        local status=""
        if [ -f "$svc/compose.yaml" ] || [ -f "$svc/compose.yml" ]; then
            status=$(docker compose ls --format json 2>/dev/null | python3 -c "
import sys, json
name = sys.argv[1]
try:
    data = json.load(sys.stdin)
    if not isinstance(data, list):
        data = [data]
    for e in data:
        if e.get('Name') == name:
            print(e.get('Status', 'unknown'))
            break
except: pass
" "$name" 2>/dev/null || echo "unknown")
        fi
        printf "  ${GREEN}%-28s${RESET} %s\n" "$name" "${status:-unknown}"
        count=$((count + 1))
    done
    echo "${CYAN}────────────────────────────────────────${RESET}"
    echo "  $count services deployed"
}

cmd_up() {
    local svc="$1"
    [ -z "$svc" ] && usage
    check_deps
    check_templates
    check_service "$svc"
    load_global_config

    local target
    target=$(service_dir "$svc")

    if [ ! -d "$target" ]; then
        log "Deploying $svc to $target"
        mkdir -p "$target/config" "$target/data"
        if [ -f "$SCALE_DIR/$svc/compose.yaml" ]; then
            cp "$SCALE_DIR/$svc/compose.yaml" "$target/"
        fi
        if [ -f "$SCALE_DIR/$svc/compose.yml" ]; then
            cp "$SCALE_DIR/$svc/compose.yml" "$target/"
        fi
    else
        mkdir -p "$target/config" "$target/data"
    fi

    local env_file="$target/.env"
    if [ ! -f "$env_file" ]; then
        if [ -f "$SCALE_DIR/$svc/.env" ]; then
            cp "$SCALE_DIR/$svc/.env" "$env_file"
        else
            cat > "$env_file" <<-EOF
SERVICE=$svc
IMAGE_URL=
SERVICEPORT=
DNS_SERVER=${DNS_SERVER:-9.9.9.9}
TS_AUTHKEY=${TS_AUTHKEY:-}
TZ=${TZ:-Europe/Amsterdam}
EOF
        fi

        if [ -n "${TS_AUTHKEY:-}" ]; then
            sed -i "s|^TS_AUTHKEY=.*|TS_AUTHKEY=$TS_AUTHKEY|" "$env_file" 2>/dev/null || true
        fi
        if [ -n "${TZ:-}" ]; then
            sed -i "s|^TZ=.*|TZ=$TZ|" "$env_file" 2>/dev/null || true
        fi
        if [ -n "${DNS_SERVER:-}" ]; then
            sed -i "s|^DNS_SERVER=.*|DNS_SERVER=$DNS_SERVER|" "$env_file" 2>/dev/null || true
        fi

        if grep -q "^TS_AUTHKEY=$" "$env_file" 2>/dev/null; then
            warn "TS_AUTHKEY is not set"
            local key
            read -rp "  Enter your Tailscale auth key (or press Enter to skip): " key
            if [ -n "$key" ]; then
                sed -i "s|^TS_AUTHKEY=.*|TS_AUTHKEY=$key|" "$env_file"
            fi
        fi
        log ".env created at $env_file"
        if confirm "Edit .env before starting?" Y; then
            "${EDITOR:-nano}" "$env_file"
            log "Continuing with startup..."
        fi
    fi

    log "Starting $svc..."
    (cd "$target" && docker compose up -d)
    ok "$svc is running"
}

cmd_down() {
    local svc="$1"
    [ -z "$svc" ] && usage
    check_deps
    load_global_config
    local target
    target=$(service_dir "$svc")
    [ -d "$target" ] || err "$svc is not deployed at $target"
    log "Stopping $svc..."
    (cd "$target" && docker compose down)
    ok "$svc stopped"
}

cmd_restart() {
    local svc="$1"
    [ -z "$svc" ] && usage
    check_deps
    load_global_config
    local target
    target=$(service_dir "$svc")
    [ -d "$target" ] || err "$svc is not deployed"
    log "Restarting $svc..."
    (cd "$target" && docker compose restart)
    ok "$svc restarted"
}

cmd_logs() {
    local svc="$1"
    shift 2>/dev/null || true
    [ -z "$svc" ] && usage
    check_deps
    load_global_config
    local target
    target=$(service_dir "$svc")
    [ -d "$target" ] || err "$svc is not deployed"
    (cd "$target" && exec docker compose logs "$@")
}

cmd_update() {
    check_templates

    log "Updating ScaleTail templates..."
    sudo git -C "/usr/local/share/linux_post_install/scale-tail" pull
    ok "Templates updated"

    load_global_config
    local refreshed=0

    [ -d "$SERVICES_BASE" ] || { ok "$refreshed compose files refreshed (.env preserved)"; return; }

    for svc in "$SERVICES_BASE"/*/; do
        [ -d "$svc" ] || continue
        local name
        name=$(basename "$svc")
        if [ -f "$SCALE_DIR/$name/compose.yaml" ]; then
            cp "$SCALE_DIR/$name/compose.yaml" "$svc/compose.yaml"
            refreshed=$((refreshed + 1))
        fi
        if [ -f "$SCALE_DIR/$name/compose.yml" ]; then
            cp "$SCALE_DIR/$name/compose.yml" "$svc/compose.yml"
            refreshed=$((refreshed + 1))
        fi
    done

    ok "$refreshed compose files refreshed (.env preserved)"
}

cmd_config() {
    local action="${1:-show}"
    shift 2>/dev/null || true

    case "$action" in
        show)
            load_global_config
            echo "${CYAN}Global compose config${RESET}"
            echo "${DIM}File: $CONFIG_ENV${RESET}"
            echo "${CYAN}────────────────────────────────────────${RESET}"
            if [ -f "$CONFIG_ENV" ]; then
                cat "$CONFIG_ENV"
            else
                echo "(no global config set — using defaults)"
            fi
            echo "${CYAN}────────────────────────────────────────${RESET}"
            echo "SERVICES_BASE=$SERVICES_BASE    (deployment directory)"
            echo "${DIM}Set with: pos docker compose config set SERVICES_BASE=/srv${RESET}"
            ;;
        set)
            local pair="${1:-}"
            [ -z "$pair" ] && usage
            local key="${pair%%=*}"
            local val="${pair#*=}"
            mkdir -p "$(dirname "$CONFIG_ENV")"
            if [ -f "$CONFIG_ENV" ] && grep -q "^${key}=" "$CONFIG_ENV" 2>/dev/null; then
                sed -i "s|^${key}=.*|${key}=${val}|" "$CONFIG_ENV"
            else
                echo "${key}=${val}" >> "$CONFIG_ENV"
            fi
            ok "Set ${key}=${val}"
            ;;
        edit)
            mkdir -p "$(dirname "$CONFIG_ENV")"
            if [ ! -f "$CONFIG_ENV" ]; then
                cat > "$CONFIG_ENV" <<-EOF
# Linux_post_install — global Docker Compose config
# Each key is optional; empty values prompt on first deploy.
TS_AUTHKEY=
TZ=Europe/Amsterdam
DNS_SERVER=9.9.9.9
SERVICES_BASE=/srv
EOF
                log "Created default config at $CONFIG_ENV"
            fi
            log "Opening $CONFIG_ENV in ${EDITOR:-nano}..."
            "${EDITOR:-nano}" "$CONFIG_ENV"
            log "Config saved"
            ;;
        *)
            usage
            ;;
    esac
}

###############################################################################
# CLI dispatch
###############################################################################

[ $# -eq 0 ] && usage

command -v docker &>/dev/null || command -v docker-compose &>/dev/null || err "docker not found — install with: sudo apt install docker.io"

case "${1:-}" in
    -h|--help) usage ;;
esac

cmd="${1:-}"
shift

case "$cmd" in
    ls)        cmd_ls ;;
    installed) cmd_installed ;;
    up)        cmd_up "${1:-}" ;;
    down)      cmd_down "${1:-}" ;;
    restart)   cmd_restart "${1:-}" ;;
    logs)      cmd_logs "$@" ;;
    update)    cmd_update ;;
    config)    cmd_config "$@" ;;
    *)         usage ;;
esac
