#!/usr/bin/env bash
#
# Dezky local development bootstrap
# Run this once when setting up the project for the first time.
#
# Usage: ./scripts/bootstrap.sh
#

set -euo pipefail

# ────────────────────────────────────────
# Colors for output
# ────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

info()    { echo -e "${BLUE}[INFO]${NC}  $*"; }
ok()      { echo -e "${GREEN}[OK]${NC}    $*"; }
warn()    { echo -e "${YELLOW}[WARN]${NC}  $*"; }
error()   { echo -e "${RED}[ERROR]${NC} $*" >&2; }

# ────────────────────────────────────────
# Determine project root
# ────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
COMPOSE_DIR="$PROJECT_ROOT/infrastructure/docker-compose"
CERTS_DIR="$COMPOSE_DIR/certs"

cd "$PROJECT_ROOT"

echo ""
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║          Dezky Local Development Bootstrap                   ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""

# ────────────────────────────────────────
# Step 1: Check prerequisites
# ────────────────────────────────────────
info "Step 1: Checking prerequisites..."

check_command() {
    if ! command -v "$1" &> /dev/null; then
        error "$1 is not installed."
        echo "       Install with: $2"
        exit 1
    fi
    ok "$1 found: $(command -v "$1")"
}

check_command docker "Install Docker Desktop or OrbStack from https://orbstack.dev"
check_command mkcert "brew install mkcert"
check_command openssl "Should be preinstalled on macOS"
check_command git "brew install git"

if ! docker compose version &> /dev/null; then
    error "Docker Compose v2 not available."
    echo "       Update Docker Desktop or install OrbStack."
    exit 1
fi
ok "Docker Compose v2 available"

# Check Docker daemon is running
if ! docker info &> /dev/null; then
    error "Docker daemon not running. Start Docker Desktop / OrbStack first."
    exit 1
fi
ok "Docker daemon running"

echo ""

# ────────────────────────────────────────
# Step 2: Configure git remote
# ────────────────────────────────────────
info "Step 2: Configuring git remote..."

GIT_REMOTE_URL="git@git.lastcloud.io:ronnibaslund/dezky.git"
GIT_SSH_HOST="git.lastcloud.io"
GIT_SSH_PORT="22222"

if [[ -d "$PROJECT_ROOT/.git" ]]; then
    CURRENT_URL="$(git -C "$PROJECT_ROOT" remote get-url origin 2>/dev/null || true)"
    if [[ "$CURRENT_URL" == "$GIT_REMOTE_URL" ]]; then
        ok "Git remote 'origin' already set to $GIT_REMOTE_URL"
    elif [[ -n "$CURRENT_URL" ]]; then
        git -C "$PROJECT_ROOT" remote set-url origin "$GIT_REMOTE_URL"
        ok "Updated git remote 'origin' → $GIT_REMOTE_URL (was $CURRENT_URL)"
    else
        git -C "$PROJECT_ROOT" remote add origin "$GIT_REMOTE_URL"
        ok "Added git remote 'origin' → $GIT_REMOTE_URL"
    fi

    # Gitea's git SSH listens on a non-standard port. Without an ssh config
    # entry, git defaults to port 22 and the global "Host *" 1Password agent
    # offers too many keys — the server rejects the connection before the right
    # key is tried. Pin the host to port 22222 and the registered key only.
    if [[ "$(ssh -G "$GIT_SSH_HOST" 2>/dev/null | awk '/^port /{print $2}')" == "$GIT_SSH_PORT" ]]; then
        ok "SSH config already routes $GIT_SSH_HOST to port $GIT_SSH_PORT"
    else
        warn "$GIT_SSH_HOST is not pinned to port $GIT_SSH_PORT in your SSH config"
        echo ""
        echo "The following block is needed in ~/.ssh/config so git can reach Gitea:"
        echo ""
        echo "  Host $GIT_SSH_HOST"
        echo "    HostName $GIT_SSH_HOST"
        echo "    Port $GIT_SSH_PORT"
        echo "    User git"
        echo "    IdentityFile ~/.ssh/id_ed25519"
        echo "    IdentitiesOnly yes"
        echo ""
        read -p "Append this block to ~/.ssh/config automatically? [y/N] " -n 1 -r
        echo ""
        if [[ $REPLY =~ ^[Yy]$ ]]; then
            mkdir -p "$HOME/.ssh"
            {
                echo ""
                echo "# Gitea (lastcloud) — Git SSH on port $GIT_SSH_PORT. Force the registered"
                echo "# key only; the global \"Host *\" agent otherwise offers too many keys."
                echo "Host $GIT_SSH_HOST"
                echo "  HostName $GIT_SSH_HOST"
                echo "  Port $GIT_SSH_PORT"
                echo "  User git"
                echo "  IdentityFile ~/.ssh/id_ed25519"
                echo "  IdentitiesOnly yes"
            } >> "$HOME/.ssh/config"
            chmod 600 "$HOME/.ssh/config"
            ok "Appended SSH config block for $GIT_SSH_HOST"
        else
            warn "Skipping SSH config — pushes to $GIT_SSH_HOST may fail until you add it"
        fi
    fi
else
    warn "No .git directory in $PROJECT_ROOT — skipping git remote setup"
fi

echo ""

# ────────────────────────────────────────
# Step 3: Generate TLS certificates
# ────────────────────────────────────────
info "Step 3: Setting up TLS certificates..."

mkdir -p "$CERTS_DIR"
cd "$CERTS_DIR"

if [[ -f "dezky.local.pem" && -f "dezky.local-key.pem" ]]; then
    ok "TLS certificates already exist in $CERTS_DIR"
else
    info "Generating wildcard certificate for *.dezky.local..."

    if ! mkcert -CAROOT &> /dev/null; then
        warn "mkcert root CA not found. Running mkcert -install..."
        mkcert -install
    fi

    mkcert "*.dezky.local" "dezky.local" "localhost" "127.0.0.1" "::1"

    # Normalize filenames (mkcert adds counts)
    mv ./_wildcard.dezky.local+*.pem dezky.local.pem 2>/dev/null || true
    mv ./_wildcard.dezky.local+*-key.pem dezky.local-key.pem 2>/dev/null || true

    ok "TLS certificates generated"
fi

cd "$PROJECT_ROOT"
echo ""

# ────────────────────────────────────────
# Step 4: Update /etc/hosts
# ────────────────────────────────────────
info "Step 4: Setting up /etc/hosts entries..."

HOSTS_ENTRIES=(
    "dezky.local"
    "www.dezky.local"
    "app.dezky.local"
    "operator.dezky.local"
    "auth.dezky.local"
    "mail.dezky.local"
    "files.dezky.local"
    "office.dezky.local"
    "meet.dezky.local"
    "chat.dezky.local"
    "traefik.dezky.local"
)

MISSING_ENTRIES=()
for entry in "${HOSTS_ENTRIES[@]}"; do
    if ! grep -q "127.0.0.1[[:space:]]\+.*\b${entry}\b" /etc/hosts; then
        MISSING_ENTRIES+=("$entry")
    fi
done

if [[ ${#MISSING_ENTRIES[@]} -eq 0 ]]; then
    ok "All /etc/hosts entries already present"
else
    warn "Missing /etc/hosts entries: ${MISSING_ENTRIES[*]}"
    echo ""
    echo "Add the following line to /etc/hosts (requires sudo):"
    echo ""
    echo "127.0.0.1  ${HOSTS_ENTRIES[*]}"
    echo ""
    read -p "Add these entries automatically? (requires sudo) [y/N] " -n 1 -r
    echo ""
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        HOSTS_LINE="127.0.0.1  ${HOSTS_ENTRIES[*]}"
        echo "$HOSTS_LINE" | sudo tee -a /etc/hosts > /dev/null
        ok "Added /etc/hosts entries"
    else
        warn "Skipping /etc/hosts setup — you must add entries manually before continuing"
    fi
fi

echo ""

# ────────────────────────────────────────
# Step 5: Generate .env file
# ────────────────────────────────────────
info "Step 5: Setting up .env file..."

if [[ -f "$PROJECT_ROOT/.env" ]]; then
    ok ".env file already exists"
else
    info "Generating .env with secure random values..."

    cp "$PROJECT_ROOT/.env.example" "$PROJECT_ROOT/.env"

    # Replace all 'changeme_*' placeholders with actual random values
    if [[ "$OSTYPE" == "darwin"* ]]; then
        SED_INPLACE=(-i '')
    else
        SED_INPLACE=(-i)
    fi

    while IFS= read -r line; do
        if [[ "$line" =~ ^([A-Z_]+)=changeme ]]; then
            VAR_NAME="${BASH_REMATCH[1]}"

            if [[ "$VAR_NAME" == "AUTHENTIK_SECRET_KEY" ]]; then
                NEW_VALUE=$(openssl rand -hex 50)
            else
                NEW_VALUE=$(openssl rand -hex 32)
            fi

            sed "${SED_INPLACE[@]}" "s|^${VAR_NAME}=changeme.*|${VAR_NAME}=${NEW_VALUE}|" "$PROJECT_ROOT/.env"
        fi
    done < "$PROJECT_ROOT/.env.example"

    ok ".env generated with secure random values"
    warn "Default admin password generated. Check .env for AUTHENTIK_BOOTSTRAP_PASSWORD"
fi

echo ""

# ────────────────────────────────────────
# Step 6: Pull Docker images
# ────────────────────────────────────────
info "Step 6: Pulling Docker images (this may take a few minutes)..."

cd "$COMPOSE_DIR"
docker compose pull
ok "All images pulled"

echo ""

# ────────────────────────────────────────
# Step 7: Start the stack in stages
# ────────────────────────────────────────
info "Step 7: Starting services..."

info "Starting database layer (postgres, mongo, redis)..."
docker compose up -d postgres mongo redis

info "Waiting for databases to be healthy..."
sleep 10
for service in postgres mongo redis; do
    until [[ "$(docker inspect --format='{{.State.Health.Status}}' dezky-$service 2>/dev/null)" == "healthy" ]]; do
        echo -n "."
        sleep 2
    done
    echo ""
    ok "$service is healthy"
done

info "Starting Traefik reverse proxy..."
docker compose up -d traefik

info "Starting Authentik..."
docker compose up -d authentik-server authentik-worker

info "Waiting 30 seconds for Authentik to bootstrap..."
sleep 30

info "Starting application services..."
docker compose up -d stalwart ocis collabora

echo ""
ok "Stack started"
echo ""

# ────────────────────────────────────────
# Final instructions
# ────────────────────────────────────────
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║                    Setup Complete                            ║"
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""
echo "Service URLs:"
echo "  Website:          https://dezky.local"
echo "  Portal:           https://app.dezky.local"
echo "  Authentik (auth): https://auth.dezky.local"
echo "  Mail (admin):     https://mail.dezky.local"
echo "  Files (OCIS):     https://files.dezky.local"
echo "  Office:           https://office.dezky.local"
echo "  Traefik:          https://traefik.dezky.local"
echo ""
echo "First-time Authentik admin login:"
echo "  URL:      https://auth.dezky.local/if/flow/initial-setup/"
echo "  Email:    admin@dezky.local"
echo "  Password: (see AUTHENTIK_BOOTSTRAP_PASSWORD in .env)"
echo ""
echo "Next steps:"
echo "  1. Configure Authentik (see docs/AUTHENTIK-SETUP.md)"
echo "  2. Configure OCIS OIDC provider in Authentik"
echo "  3. Start building the portal in apps/portal/"
echo ""
echo "Useful commands:"
echo "  Logs:   docker compose -f $COMPOSE_DIR/docker-compose.yml logs -f [service]"
echo "  Stop:   docker compose -f $COMPOSE_DIR/docker-compose.yml down"
echo "  Reset:  $PROJECT_ROOT/scripts/reset.sh"
echo ""
