#!/bin/bash
set -euo pipefail

# ═══════════════════════════════════════════════════
# Ultima v5.5 — macOS One-Click Installer [STABLE]
# ═══════════════════════════════════════════════════
# Запуск: bash install-ultima-macos.sh
# ═══════════════════════════════════════════════════

VERSION="5.5.0"
ULTIMA_ROOT="$HOME/Ultima"
ULTIMA_DATA="$HOME/Library/Application Support/Ultima"
ULTIMA_CONFIG="$HOME/Library/Application Support/Ultima"
OBSIDIAN_VAULT="$HOME/Ultima Memory"
LOG_FILE="/tmp/ultima-install-$(date +%Y%m%d-%H%M%S).log"
OPENROUTER_API_KEY="${OPENROUTER_API_KEY:-}"

DEFAULT_MODEL="deepseek/deepseek-v4-flash:free"
# ★ Ultima 5.5: fallback_model удалён — death spiral fix
# opencode web НЕ поддерживает этот ключ

MAX_CPU_PERCENT=80
MAX_RAM_MB=4096

RED='\033[0;31m'; GREEN='\033[0;32m'; CYAN='\033[0;36m'; YELLOW='\033[1;33m'; NC='\033[0m'; BOLD='\033[1m'

log()   { echo -e "${GREEN}[✓]${NC} $1"; echo "[$(date +%H:%M:%S)] [OK] $1" >> "$LOG_FILE"; }
warn()  { echo -e "${YELLOW}[!]${NC} $1"; echo "[$(date +%H:%M:%S)] [WARN] $1" >> "$LOG_FILE"; }
error() { echo -e "${RED}[✗]${NC} $1"; echo "[$(date +%H:%M:%S)] [ERROR] $1" >> "$LOG_FILE"; }
info()  { echo -e "${CYAN}[i]${NC} $1"; echo "[$(date +%H:%M:%S)] [INFO] $1" >> "$LOG_FILE"; }
step()  { echo ""; echo -e "${CYAN}════════════════════════════════════════${NC}"; echo -e "${CYAN}  $1${NC}"; echo -e "${CYAN}════════════════════════════════════════${NC}"; echo "[$(date +%H:%M:%S)] [STEP] $1" >> "$LOG_FILE"; }

# ═══════════════════════════════════════════════════
# BANNER
# ═══════════════════════════════════════════════════

clear
echo ""
echo -e "${CYAN}${BOLD}"
echo "  ╔══════════════════════════════════════════════╗"
echo "  ║      Ultima v$VERSION — macOS Installer        ║"
echo "  ║                                              ║"
echo "  ║  Python + Docker + Obsidian + ChromaDB        ║"
echo "  ║  Для полной установки наберись терпения       ║"
echo "  ╚══════════════════════════════════════════════╝"
echo -e "${NC}"
echo "  Log: $LOG_FILE"
echo ""

# ═══════════════════════════════════════════════════
# PHASE 1: Prerequisites
# ═══════════════════════════════════════════════════

step "Фаза 1: Проверка системы"

# macOS version
sw_vers &>/dev/null || { error "Это не macOS. Установщик только для Mac."; exit 1; }
log "macOS: $(sw_vers -productVersion) ($(sw_vers -buildVersion))"

# Architecture
ARCH=$(uname -m)
log "Архитектура: $ARCH"

# Disk space
FREE_GB=$(df -h / | awk 'NR==2{print $4}')
log "Место на диске: $FREE_GB"

# RAM
RAM_GB=$(sysctl hw.memsize | awk '{printf "%.1f", $2/1073741824}')
log "RAM: $RAM_GB GB"

# Internet check
if curl -s --connect-timeout 8 https://www.apple.com >/dev/null 2>&1; then
    log "Интернет — OK"
else
    warn "Интернет не отвечает. Установка продолжится, но winget/brew могут не сработать."
fi

# Rosetta 2 for Apple Silicon
if [ "$ARCH" = "arm64" ]; then
    if ! arch -x86_64 /usr/bin/true 2>/dev/null; then
        info "Установка Rosetta 2..."
        softwareupdate --install-rosetta --agree-to-license 2>&1 | tail -1 || true
        log "Rosetta 2 установлена"
    else
        log "Rosetta 2 — OK"
    fi
fi

# ═══════════════════════════════════════════════════
# PHASE 2: Xcode Command Line Tools
# ═══════════════════════════════════════════════════

step "Фаза 2: Xcode Command Line Tools"

if xcode-select -p &>/dev/null; then
    log "Xcode CLT — OK"
else
    info "Установка Xcode Command Line Tools..."
    xcode-select --install 2>/dev/null || true
    warn "Дождись установки Xcode CLT в всплывающем окне, затем нажми Enter"
    read -rp "  Готово? Нажми Enter..."
    log "Xcode CLT установлены"
fi

# ═══════════════════════════════════════════════════
# PHASE 3: Homebrew
# ═══════════════════════════════════════════════════

step "Фаза 3: Homebrew"

if command -v brew &>/dev/null; then
    log "Homebrew: $(brew --version | head -1)"
else
    info "Установка Homebrew..."
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 2>&1 | tail -3 || true
    
    # Add to PATH for Apple Silicon
    if [ "$ARCH" = "arm64" ] && [ -f /opt/homebrew/bin/brew ]; then
        eval "$(/opt/homebrew/bin/brew shellenv)"
    fi
    
    if command -v brew &>/dev/null; then
        log "Homebrew установлен"
    else
        error "Homebrew не установился. Установи вручную: https://brew.sh"
        exit 1
    fi
fi

brew update --quiet 2>&1 | tail -1 || true

# ═══════════════════════════════════════════════════
# PHASE 4: Install Packages
# ═══════════════════════════════════════════════════

step "Фаза 4: Установка пакетов"

install_brew() {
    local pkg=$1
    if brew list "$pkg" &>/dev/null 2>&1; then
        log "$pkg — уже установлен"
    else
        echo -n "    → $pkg... "
        brew install "$pkg" --quiet 2>&1 | tail -1 || true
        if brew list "$pkg" &>/dev/null 2>&1; then
            echo -e "${GREEN}OK${NC}"
        else
            echo -e "${RED}FAILED${NC}"
            warn "Ошибка установки $pkg"
        fi
    fi
}

install_brew_cask() {
    local pkg=$1
    local name=$2
    if brew list --cask "$pkg" &>/dev/null 2>&1; then
        log "$name — уже установлен"
    else
        echo -n "    → $name... "
        brew install --cask "$pkg" --quiet 2>&1 | tail -1 || true
        if brew list --cask "$pkg" &>/dev/null 2>&1; then
            echo -e "${GREEN}OK${NC}"
        else
            echo -e "${YELLOW}(пропущено)${NC}"
            warn "Ошибка установки $name. Можно установить вручную."
        fi
    fi
}

install_brew "python@3.11"
install_brew "git"
install_brew_cask "docker" "Docker Desktop"
install_brew_cask "obsidian" "Obsidian"

# ═══════════════════════════════════════════════════
# PHASE 5: Directory Structure
# ═══════════════════════════════════════════════════

step "Фаза 5: Создание структуры директорий"

mkdir -p "$ULTIMA_ROOT"/{configs/instructions,personality,scripts/orchestrator,skills,memory/{chroma,obsidian/{journal,knowledge-base,projects,rules}},.sisyphus/{sops,agents},build}
mkdir -p "$ULTIMA_DATA/chroma"
mkdir -p "$ULTIMA_CONFIG"
mkdir -p "$OBSIDIAN_VAULT"/{journal,knowledge-base,projects,rules}

log "Структура создана в $ULTIMA_ROOT"

# ═══════════════════════════════════════════════════
# PHASE 6: Python Virtual Environment
# ═══════════════════════════════════════════════════

step "Фаза 6: Python-зависимости"

PYTHON_BIN=$(brew --prefix python@3.11)/bin/python3.11
VENV_PATH="$ULTIMA_ROOT/.venv"

if [ ! -f "$VENV_PATH/bin/python3" ]; then
    echo -n "    → Виртуальное окружение... "
    "$PYTHON_BIN" -m venv "$VENV_PATH"
    echo -e "${GREEN}OK${NC}"
else
    log "Виртуальное окружение уже существует"
fi

PIP="$VENV_PATH/bin/pip"
PYTHON="$VENV_PATH/bin/python"

echo -n "    → Обновление pip... "
$PIP install --upgrade pip --quiet 2>/dev/null && echo -e "${GREEN}OK${NC}" || echo -e "${RED}FAILED${NC}"

PACKAGES=(
    "chromadb>=0.4.0"
    "openai>=1.0.0"
    "pyyaml>=6.0"
    "requests>=2.28.0"
    "fastapi>=0.100.0"
    "uvicorn[standard]>=0.20.0"
    "pydantic>=2.0.0"
    "python-dotenv>=1.0.0"
    "httpx>=0.24.0"
    "rich>=13.0.0"
)

echo "    → Установка пакетов..."
for pkg in "${PACKAGES[@]}"; do
    echo -n "      ⬡ $pkg... "
    if $PIP install "$pkg" --quiet 2>/dev/null; then
        echo -e "${GREEN}✓${NC}"
    else
        echo -e "${RED}✗${NC}"
    fi
done

log "Python-зависимости установлены"

# Check ChromaDB
CHROMA_VER=$($PYTHON -c "import chromadb; print(chromadb.__version__)" 2>/dev/null || echo "")
if [ -n "$CHROMA_VER" ]; then
    log "ChromaDB v$CHROMA_VER — OK"
else
    error "ChromaDB не установилась"
fi

# ═══════════════════════════════════════════════════
# PHASE 7: Install OpenCode Binary
# ═══════════════════════════════════════════════════

step "Фаза 7: Установка OpenCode CLI"

OPENCODE_DIR="$HOME/.opencode/bin"
OPENCODE_BIN="$OPENCODE_DIR/opencode"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"

if [ -f "$OPENCODE_BIN" ]; then
    OPENCODE_VER=$("$OPENCODE_BIN" --version 2>/dev/null || echo "old")
    log "OpenCode CLI v$OPENCODE_VER — уже установлен"
elif [ -f "$SCRIPT_DIR/opencode-macos.gz" ]; then
    echo -n "    → Распаковка opencode... "
    mkdir -p "$OPENCODE_DIR"
    gunzip -c "$SCRIPT_DIR/opencode-macos.gz" > "$OPENCODE_BIN"
    chmod +x "$OPENCODE_BIN"
    echo -e "${GREEN}OK${NC}"
    OPENCODE_VER=$("$OPENCODE_BIN" --version 2>/dev/null || echo "?")
    log "OpenCode CLI v$OPENCODE_VER — установлен в $OPENCODE_BIN"
elif [ -f "$SCRIPT_DIR/opencode-macos" ]; then
    echo -n "    → Копирование opencode... "
    mkdir -p "$OPENCODE_DIR"
    cp "$SCRIPT_DIR/opencode-macos" "$OPENCODE_BIN"
    chmod +x "$OPENCODE_BIN"
    echo -e "${GREEN}OK${NC}"
    OPENCODE_VER=$("$OPENCODE_BIN" --version 2>/dev/null || echo "?")
    log "OpenCode CLI v$OPENCODE_VER — установлен в $OPENCODE_BIN"
else
    warn "opencode-macos.gz не найден рядом с установщиком."
    warn "Скачай opencode вручную и положи в ~/.opencode/bin/opencode"
    warn "Или установи через: curl -fsSL https://opencode.ai/install | sh"
fi

# Add to PATH in .zshrc if not already there
if [ -d "$OPENCODE_DIR" ]; then
    if [ -f "$HOME/.zshrc" ] && ! grep -q "\.opencode/bin" "$HOME/.zshrc" 2>/dev/null; then
        echo 'export PATH="$PATH:$HOME/.opencode/bin"' >> "$HOME/.zshrc"
        log "OpenCode добавлен в PATH (~/.zshrc)"
    elif [ ! -f "$HOME/.zshrc" ]; then
        echo 'export PATH="$PATH:$HOME/.opencode/bin"' > "$HOME/.zshrc"
        log "Создан ~/.zshrc с OpenCode в PATH"
    fi
    export PATH="$PATH:$OPENCODE_DIR"
fi

# ═══════════════════════════════════════════════════
# PHASE 8: Extract All Skills (49 шт.)
# ═══════════════════════════════════════════════════

step "Фаза 8: Распаковка всех скиллов (49)"

SKILLS_ARCHIVE="$SCRIPT_DIR/skills.tar.gz"
if [ -f "$SKILLS_ARCHIVE" ]; then
    echo -n "    → Распаковка 49 скиллов... "
    tar -xzf "$SKILLS_ARCHIVE" -C "$ULTIMA_ROOT/skills/" 2>/dev/null
    if [ $? -eq 0 ]; then
        echo -e "${GREEN}OK${NC}"
        SKILL_COUNT=$(find "$ULTIMA_ROOT/skills" -name "SKILL.md" | wc -l)
        log "Скиллы: $SKILL_COUNT SKILL.md распаковано"
    else
        echo -e "${RED}FAILED${NC}"
        warn "Не удалось распаковать архивы скиллов"
    fi
else
    warn "skills.tar.gz не найден рядом с установщиком"
    warn "Останется только 5 базовых скиллов. Полный набор (49) не установлен."
fi

# ═══════════════════════════════════════════════════
# PHASE 9: Configuration
# ═══════════════════════════════════════════════════

step "Фаза 9: Настройка конфигурации"

# opencode.json
cat > "$ULTIMA_ROOT/configs/opencode.json" << JSONEOF
{
  "version": "$VERSION",
  "name": "Ultima",
  "description": "Автономная AI-платформа",
  "model": "$DEFAULT_MODEL",
  "personality": {
    "name": "Ultima",
    "gender": "female",
    "style": "techno-geek punk-rocker",
    "language": "ru"
  },
  "skills": {
    "feature-dev": { "trigger": ["feature", "разработка"] },
    "ichor": { "trigger": ["текст", "копирайтинг"] },
    "web-research": { "trigger": ["поиск", "research"] }
  },
  "budgets": {
    "max_steps_per_session": 20,
    "max_cost_per_session_usd": 5,
    "max_retries": 3
  }
}
JSONEOF
log "opencode.json — создан"

# .env
ENV_PATH="$ULTIMA_CONFIG/.env"
if [ ! -f "$ENV_PATH" ]; then
    if [ -z "$OPENROUTER_API_KEY" ]; then
        echo ""
        warn "OPENROUTER_API_KEY не найден."
        echo -e "${YELLOW}  Введи API-ключ OpenRouter (https://openrouter.ai/keys):${NC}"
        echo -e "${DARK}  (Enter — пропустить, введёшь позже)${NC}"
        read -rp "  OPENROUTER_API_KEY: " OPENROUTER_API_KEY
    fi

    cat > "$ENV_PATH" << ENVEOF
# Ultima v$VERSION — API Keys
# Created: $(date '+%Y-%m-%d %H:%M')
OPENROUTER_API_KEY=$OPENROUTER_API_KEY
DEFAULT_MODEL=$DEFAULT_MODEL
MAX_CPU_PERCENT=$MAX_CPU_PERCENT
MAX_RAM_MB=$MAX_RAM_MB
ULTIMA_ROOT=$ULTIMA_ROOT
ULTIMA_DATA=$ULTIMA_DATA
OBSIDIAN_VAULT=$OBSIDIAN_VAULT
ENVEOF
    log ".env — создан"
else
    log ".env — уже существует"
fi

# Security rules
cat > "$ULTIMA_ROOT/SECURITY.md" << SECEOF
# Ultima v$VERSION — Security Rules
## Лимиты
- CPU: не более $MAX_CPU_PERCENT%
- RAM: не более $MAX_RAM_MB MB для Python-процессов
## Запреты
- Запуск от имени root
- Изменение системных файлов
- Майнинг и ресурсоёмкие фоновые задачи
SECEOF
log "Правила безопасности — созданы"

# ═══════════════════════════════════════════════════
# PHASE 10: macOS Security (launchd limits)
# ═══════════════════════════════════════════════════

step "Фаза 10: Настройка безопасности macOS"

# Create launchd plist for resource limits
cat > "$HOME/Library/LaunchAgents/com.ultima.resourceguard.plist" << PLISTEOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.ultima.resourceguard</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>-c</string>
        <string>while true; do for pid in \$(pgrep -f "python.*ultima" 2>/dev/null); do renice +10 \$pid 2>/dev/null; done; sleep 30; done</string>
    </array>
    <key>RunAtLoad</key>
    <false/>
    <key>KeepAlive</key>
    <false/>
    <key>StandardOutPath</key>
    <string>/tmp/ultima-resourceguard.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/ultima-resourceguard.log</string>
</dict>
</plist>
PLISTEOF

# Don't load by default — user enables via alias
log "Resource Guard plist — создан (отключён, включается при запуске Ultima)"

# Create the resource guard script
cat > "$ULTIMA_ROOT/scripts/resource-guard.sh" << 'GUARDEOF'
#!/bin/bash
# Ultima Resource Guard — защита от перегрузки
while true; do
    for pid in $(pgrep -f "python.*ultima" 2>/dev/null); do
        renice +10 "$pid" 2>/dev/null
    done
    sleep 30
done
GUARDEOF
chmod +x "$ULTIMA_ROOT/scripts/resource-guard.sh"
log "Resource Guard скрипт — создан"

# ═══════════════════════════════════════════════════
# PHASE 11: Desktop Aliases

step "Фаза 11: Создание ярлыков"

DESKTOP="$HOME/Desktop"

# Create Ultima launcher script
cat > "$ULTIMA_ROOT/start-ultima.sh" << STARTEOF
#!/bin/bash
export OPENROUTER_API_KEY="\$(grep OPENROUTER_API_KEY "\$HOME/Library/Application Support/Ultima/.env" | cut -d= -f2-)"
cd "$ULTIMA_ROOT"
source ".venv/bin/activate"
echo "Ultima v$VERSION — запуск..."
echo "API Key: \${OPENROUTER_API_KEY:0:8}..."
export PATH="\$PATH:\$HOME/.opencode/bin"
exec opencode
STARTEOF
chmod +x "$ULTIMA_ROOT/start-ultima.sh"
log "Скрипт запуска — создан"

# Create macOS alias on desktop
if [ ! -e "$DESKTOP/Ultima 5.5" ]; then
    # Create a .command file (double-clickable in Finder)
    cat > "$DESKTOP/Ultima 5.5.command" << CMDF
#!/bin/bash
cd "$ULTIMA_ROOT"
export PATH="\$PATH:\$HOME/.opencode/bin"
exec opencode
CMDF
    chmod +x "$DESKTOP/Ultima 5.5.command"
    log "Ярлык на рабочем столе — создан (Ultima 5.5.command)"
else
    log "Ярлык — уже существует"
fi

# Create Stop Ultima shortcut
cat > "$DESKTOP/Stop Ultima.command" << STOPCMD
#!/bin/bash
echo "Остановка Ultima..."
pkill -f "python.*ultima" 2>/dev/null || echo "Ultima не запущена"
echo "Готово"
STOPCMD
chmod +x "$DESKTOP/Stop Ultima.command"
log "Ярлык остановки — создан"

# ═══════════════════════════════════════════════════
# PHASE 12: Obsidian Vault

step "Фаза 12: Obsidian vault"

if [ ! -f "$OBSIDIAN_VAULT/README.md" ]; then
    cat > "$OBSIDIAN_VAULT/README.md" << VAULTEOF
# Ultima Memory Vault

Создано: $(date '+%Y-%m-%d %H:%M')
Версия Ultima: $VERSION

## Структура
- journal/ — дневники и логи сессий
- knowledge-base/ — база знаний
- projects/ — проекты
- rules/ — правила и SOPs

Ultima использует этот vault для долговременной памяти.
VAULTEOF
    log "Obsidian vault создан: $OBSIDIAN_VAULT"
else
    log "Obsidian vault — уже существует"
fi

# ═══════════════════════════════════════════════════
# PHASE 13: Verification

step "Фаза 13: Верификация"

ERRORS=0

verify() {
    local msg=$1
    shift
    if "$@" &>/dev/null; then
        log "$msg"
    else
        error "$msg — FAILED"
        ERRORS=$((ERRORS+1))
    fi
}

verify "Python 3.11" "$PYTHON_BIN" --version
verify "Git" git --version
verify "Виртуальное окружение" test -f "$VENV_PATH/bin/python3"
verify "opencode.json" test -f "$ULTIMA_ROOT/configs/opencode.json"
verify ".env" test -f "$ENV_PATH"
verify "Директория Ultima" test -d "$ULTIMA_ROOT"
verify "ChromaDB" $PYTHON -c "import chromadb"
verify "OpenCode CLI" test -f "$HOME/.opencode/bin/opencode"

SKILL_COUNT=$(find "$ULTIMA_ROOT/skills" -name "SKILL.md" 2>/dev/null | wc -l)
if [ "$SKILL_COUNT" -ge 49 ]; then
    log "Скиллы: $SKILL_COUNT SKILL.md — OK"
elif [ "$SKILL_COUNT" -gt 0 ]; then
    warn "Скиллы: $SKILL_COUNT из 49 (неполный набор)"
else
    error "Скиллы: 0 — не установлены"
    ERRORS=$((ERRORS+1))
fi

if command -v docker &>/dev/null; then
    log "Docker: $(docker --version 2>/dev/null)"
else
    warn "Docker: не найден (опционально, для расширенных функций)"
fi

if open -Ra "Obsidian" 2>/dev/null; then
    log "Obsidian — OK"
else
    warn "Obsidian: не найден (можно установить из https://obsidian.md)"
fi

echo ""
step "РЕЗУЛЬТАТ"

if [ $ERRORS -eq 0 ]; then
    echo ""
    echo -e "${GREEN}${BOLD}"
    echo "  ╔══════════════════════════════════════════════╗"
    echo "  ║     ULTIMA 5.5 — УСТАНОВЛЕНА ✓ [STABLE]               ║"
    echo "  ╚══════════════════════════════════════════════╝"
    echo -e "${NC}"
    echo "  Путь:     $ULTIMA_ROOT"
    echo "  Память:   $OBSIDIAN_VAULT"
    echo "  Конфиг:   $ULTIMA_ROOT/configs"
    echo "  Лог:      $LOG_FILE"
    echo ""
    echo -e "  Запуск:   ${YELLOW}дважды кликни 'Ultima 5.5.command' на рабочем столе${NC}"
    echo ""
    echo -e "  Или в терминале: ${CYAN}$ULTIMA_ROOT/start-ultima.sh${NC}"
    echo ""
else
    echo ""
    echo -e "${RED}  $ERRORS ошибок. Проверь лог: $LOG_FILE${NC}"
    echo ""
fi

echo ""
read -rp "Нажми Enter для выхода"
