#Requires -RunAsAdministrator
<#
.SYNOPSIS
    ClaudeTools Bootstrap / Reinstall Script
.DESCRIPTION
    One-and-done script to restore a complete ClaudeTools development environment
    after a fresh Windows 11 install. Idempotent - safe to re-run at any time.
.NOTES
    Run from an elevated PowerShell prompt:
        Set-ExecutionPolicy Bypass -Scope Process -Force
        .\bootstrap.ps1

    Optional flags:
        -SkipPhase <number>    Skip a specific phase (1-9)
        -OnlyPhase <number>    Run only a specific phase (1-9)
        -Archive               Create pre-reinstall archive instead of installing
        -ArchivePath <path>    Custom archive output path (default: D:\ClaudeTools-backup.zip)
#>

param(
    [int[]]$SkipPhase = @(),
    [int]$OnlyPhase = 0,
    [switch]$Archive,
    [string]$ArchivePath = "D:\ClaudeTools-backup.zip"
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Continue"

# ---------------------------------------------------------------------------
# Globals
# ---------------------------------------------------------------------------
$Script:ClaudeToolsRoot = "D:\ClaudeTools"
$Script:GiteaRepo = "https://git.azcomputerguru.com/azcomputerguru/claudetools.git"
$Script:ClaudeConfigDir = Join-Path $env:USERPROFILE ".claude"
$Script:ClaudeCommandsDir = Join-Path $Script:ClaudeConfigDir "commands"
$Script:MemoryDir = Join-Path $Script:ClaudeConfigDir "projects\D--ClaudeTools\memory"
$Script:Errors = [System.Collections.Generic.List[string]]::new()
$Script:Warnings = [System.Collections.Generic.List[string]]::new()
$Script:Successes = [System.Collections.Generic.List[string]]::new()
$Script:Skipped = [System.Collections.Generic.List[string]]::new()

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
function Write-Status {
    param(
        [string]$Prefix,
        [string]$Message,
        [ConsoleColor]$Color = [ConsoleColor]::White
    )
    Write-Host "[$Prefix] " -ForegroundColor $Color -NoNewline
    Write-Host $Message
}

function Write-OK      { param([string]$Msg) Write-Status "OK"      $Msg Green;   $Script:Successes.Add($Msg) }
function Write-Err     { param([string]$Msg) Write-Status "ERROR"   $Msg Red;     $Script:Errors.Add($Msg) }
function Write-Warn    { param([string]$Msg) Write-Status "WARNING" $Msg Yellow;  $Script:Warnings.Add($Msg) }
function Write-Skip    { param([string]$Msg) Write-Status "SKIP"    $Msg Cyan;    $Script:Skipped.Add($Msg) }
function Write-Info    { param([string]$Msg) Write-Status "INFO"    $Msg White }
function Write-Phase   { param([int]$Num, [string]$Title)
    Write-Host ""
    Write-Host ("=" * 70) -ForegroundColor Magenta
    Write-Host "  Phase ${Num}: $Title" -ForegroundColor Magenta
    Write-Host ("=" * 70) -ForegroundColor Magenta
    Write-Host ""
}

function Test-CommandExists {
    param([string]$Command)
    $null -ne (Get-Command $Command -ErrorAction SilentlyContinue)
}

function Refresh-PathEnv {
    # Reload PATH from registry so newly-installed tools are visible
    $machinePath = [System.Environment]::GetEnvironmentVariable("Path", "Machine")
    $userPath    = [System.Environment]::GetEnvironmentVariable("Path", "User")
    $env:Path = "$machinePath;$userPath"
}

function Install-WingetPackage {
    param(
        [string]$PackageId,
        [string]$FriendlyName,
        [string]$VersionHint = ""
    )

    # Check if already installed via winget list
    $installed = winget list --id $PackageId 2>$null
    if ($LASTEXITCODE -eq 0 -and $installed -match $PackageId) {
        Write-Skip "$FriendlyName is already installed"
        return $true
    }

    Write-Info "Installing $FriendlyName ($PackageId)..."
    $args = @("install", "--id", $PackageId, "--accept-source-agreements", "--accept-package-agreements", "--silent")
    if ($VersionHint) {
        $args += @("--version", $VersionHint)
    }
    $result = & winget @args 2>&1
    if ($LASTEXITCODE -eq 0) {
        Write-OK "$FriendlyName installed successfully"
        return $true
    } else {
        # winget sometimes returns non-zero even on success (already installed race)
        $resultText = $result -join "`n"
        if ($resultText -match "already installed" -or $resultText -match "No applicable update") {
            Write-Skip "$FriendlyName is already installed"
            return $true
        }
        Write-Err "Failed to install $FriendlyName : $resultText"
        return $false
    }
}

function ShouldRunPhase {
    param([int]$PhaseNum)
    if ($OnlyPhase -gt 0) { return $PhaseNum -eq $OnlyPhase }
    return $PhaseNum -notin $SkipPhase
}

# ---------------------------------------------------------------------------
# Archive Mode: Create pre-reinstall backup
# ---------------------------------------------------------------------------
function Invoke-Archive {
    Write-Phase 0 "Creating Pre-Reinstall Archive"

    $tempStaging = Join-Path $env:TEMP "claudetools-archive-staging"
    if (Test-Path $tempStaging) { Remove-Item $tempStaging -Recurse -Force }
    New-Item -ItemType Directory -Path $tempStaging -Force | Out-Null

    # Create subdirectories in staging
    $ctDest = Join-Path $tempStaging "ClaudeTools"
    $memDest = Join-Path $tempStaging "claude-memory"

    # Copy ClaudeTools repo (exclude node_modules, __pycache__, venv, .git large objects)
    Write-Info "Copying ClaudeTools repository..."
    if (Test-Path $Script:ClaudeToolsRoot) {
        $robocopyArgs = @(
            $Script:ClaudeToolsRoot, $ctDest,
            "/E", "/NFL", "/NDL", "/NJH", "/NJS",
            "/XD", "node_modules", "__pycache__", "venv", ".venv", ".mypy_cache"
        )
        & robocopy @robocopyArgs | Out-Null
        Write-OK "ClaudeTools repository copied"
    } else {
        Write-Err "ClaudeTools directory not found at $Script:ClaudeToolsRoot"
    }

    # Copy Claude memory/config
    Write-Info "Copying Claude configuration and memory..."
    if (Test-Path $Script:ClaudeConfigDir) {
        $memSrc = $Script:ClaudeConfigDir
        & robocopy $memSrc (Join-Path $tempStaging "claude-config") /E /NFL /NDL /NJH /NJS /XD "node_modules" | Out-Null
        Write-OK "Claude configuration copied"
    } else {
        Write-Warn "Claude config directory not found at $Script:ClaudeConfigDir"
    }

    # Compress
    Write-Info "Compressing archive to $ArchivePath ..."
    if (Test-Path $ArchivePath) { Remove-Item $ArchivePath -Force }
    Compress-Archive -Path "$tempStaging\*" -DestinationPath $ArchivePath -CompressionLevel Optimal
    Write-OK "Archive created: $ArchivePath"

    # Cleanup staging
    Remove-Item $tempStaging -Recurse -Force

    $sizeMB = [math]::Round((Get-Item $ArchivePath).Length / 1MB, 1)
    Write-Host ""
    Write-OK "Archive complete: $ArchivePath ($sizeMB MB)"
    Write-Info "Copy this file to external storage before reinstalling Windows."
}

# ---------------------------------------------------------------------------
# Phase 1: Prerequisites
# ---------------------------------------------------------------------------
function Invoke-Phase1 {
    Write-Phase 1 "Prerequisites Installation (winget)"

    if (-not (Test-CommandExists "winget")) {
        Write-Err "winget is not available. Please install App Installer from the Microsoft Store."
        return
    }

    Install-WingetPackage "Git.Git"                "Git"
    Install-WingetPackage "OpenJS.NodeJS"           "Node.js (Latest LTS)"
    Install-WingetPackage "Python.Python.3.13"      "Python 3.13"
    Install-WingetPackage "Ollama.Ollama"           "Ollama"

    # Refresh PATH so subsequent phases see the new installs
    Refresh-PathEnv

    # Verify critical tools are now on PATH
    foreach ($tool in @("git", "node", "python", "ollama")) {
        if (Test-CommandExists $tool) {
            $ver = & $tool --version 2>&1 | Select-Object -First 1
            Write-OK "$tool found: $ver"
        } else {
            Write-Warn "$tool not found on PATH after install. You may need to restart your terminal."
        }
    }
}

# ---------------------------------------------------------------------------
# Phase 2: Claude Code + Global NPM Packages
# ---------------------------------------------------------------------------
function Invoke-Phase2 {
    Write-Phase 2 "Claude Code and Global NPM Packages"

    if (-not (Test-CommandExists "npm")) {
        Refresh-PathEnv
        if (-not (Test-CommandExists "npm")) {
            Write-Err "npm not found. Node.js installation may have failed."
            return
        }
    }

    $npmPackages = @(
        @{ Name = "@anthropic-ai/claude-code"; Cmd = "claude" },
        @{ Name = "clawhub";   Cmd = "clawhub" },
        @{ Name = "mcporter";  Cmd = "mcporter" },
        @{ Name = "openclaw";  Cmd = "openclaw" }
    )

    foreach ($pkg in $npmPackages) {
        # Check if already installed globally
        $installed = npm list -g $($pkg.Name) --depth=0 2>$null
        if ($LASTEXITCODE -eq 0 -and $installed -match $pkg.Name) {
            Write-Skip "$($pkg.Name) is already installed globally"
        } else {
            Write-Info "Installing $($pkg.Name) globally..."
            npm install -g $($pkg.Name) 2>&1 | Out-Null
            if ($LASTEXITCODE -eq 0) {
                Write-OK "$($pkg.Name) installed"
            } else {
                Write-Err "Failed to install $($pkg.Name)"
            }
        }
    }
}

# ---------------------------------------------------------------------------
# Phase 3: Clone or Configure ClaudeTools Repository
# ---------------------------------------------------------------------------
function Invoke-Phase3 {
    Write-Phase 3 "ClaudeTools Repository"

    if (-not (Test-CommandExists "git")) {
        Refresh-PathEnv
        if (-not (Test-CommandExists "git")) {
            Write-Err "git not found. Cannot proceed with repository setup."
            return
        }
    }

    if (Test-Path (Join-Path $Script:ClaudeToolsRoot ".git")) {
        Write-Skip "ClaudeTools repository already exists at $Script:ClaudeToolsRoot"
        Write-Info "Configuring git for self-signed certificate..."
        Push-Location $Script:ClaudeToolsRoot
        git config http.sslVerify false 2>&1 | Out-Null
        Pop-Location
        Write-OK "Git SSL verification disabled for self-signed Gitea cert"

        # Ensure remote is correct
        Push-Location $Script:ClaudeToolsRoot
        $currentRemote = git remote get-url origin 2>$null
        if ($currentRemote -ne $Script:GiteaRepo) {
            git remote set-url origin $Script:GiteaRepo 2>&1 | Out-Null
            Write-OK "Git remote updated to $Script:GiteaRepo"
        } else {
            Write-OK "Git remote is correct"
        }
        Pop-Location
    }
    elseif (Test-Path $Script:ClaudeToolsRoot) {
        # Directory exists but is not a git repo (restored from archive)
        Write-Info "Directory exists but is not a git repo. Initializing..."
        Push-Location $Script:ClaudeToolsRoot
        git init 2>&1 | Out-Null
        git remote add origin $Script:GiteaRepo 2>&1 | Out-Null
        git config http.sslVerify false 2>&1 | Out-Null
        git fetch origin 2>&1 | Out-Null
        git checkout -B main origin/main 2>&1 | Out-Null
        Pop-Location
        Write-OK "Repository initialized from archive and connected to remote"
    }
    else {
        # Fresh clone
        Write-Info "Cloning ClaudeTools repository..."
        # Ensure D:\ exists
        if (-not (Test-Path "D:\")) {
            Write-Err "D:\ drive not found. Cannot clone repository."
            return
        }
        git clone -c http.sslVerify=false $Script:GiteaRepo $Script:ClaudeToolsRoot 2>&1
        if ($LASTEXITCODE -eq 0) {
            Push-Location $Script:ClaudeToolsRoot
            git config http.sslVerify false 2>&1 | Out-Null
            Pop-Location
            Write-OK "Repository cloned successfully"
        } else {
            Write-Err "Failed to clone repository"
        }
    }
}

# ---------------------------------------------------------------------------
# Phase 4: Python Environment
# ---------------------------------------------------------------------------
function Invoke-Phase4 {
    Write-Phase 4 "Python Packages (Global pip install)"

    if (-not (Test-CommandExists "python")) {
        Refresh-PathEnv
        if (-not (Test-CommandExists "python")) {
            Write-Err "python not found. Python installation may have failed."
            return
        }
    }

    $pyVersion = python --version 2>&1
    Write-OK "Python detected: $pyVersion"

    # Full list of required packages with pinned versions
    $pipPackages = @(
        "alembic==1.13.1",
        "annotated-types==0.7.0",
        "anyio==4.12.1",
        "argon2-cffi==25.1.0",
        "argon2-cffi-bindings==25.1.0",
        "bcrypt==5.0.0",
        "beautifulsoup4==4.13.5",
        "certifi==2026.1.4",
        "cffi==2.0.0",
        "claude-agent-sdk==0.1.19",
        "claude-code-sdk==0.0.25",
        "click==8.3.1",
        "colorama==0.4.6",
        "compressed-rtf==1.0.6",
        "cryptography==46.0.3",
        "easygui==0.98.3",
        "extract-msg==0.55.0",
        "fastapi==0.128.0",
        "google-api-core==2.30.0",
        "google-api-python-client==2.192.0",
        "google-auth==2.49.0",
        "google-auth-httplib2==0.3.0",
        "googleapis-common-protos==1.73.0",
        "greenlet==3.3.0",
        "httpcore==1.0.9",
        "httplib2==0.31.2",
        "httpx==0.28.1",
        "httpx-sse==0.4.3",
        "invoke==2.2.1",
        "jsonschema==4.26.0",
        "lark==1.3.1",
        "Mako==1.3.10",
        "MarkupSafe==3.0.3",
        "mcp==1.25.0",
        "msoffcrypto-tool==5.4.2",
        "numpy==2.4.2",
        "olefile==0.47",
        "oletools==0.60.2",
        "opencv-python==4.13.0.90",
        "paramiko==4.0.0",
        "passlib==1.7.4",
        "pillow==12.1.0",
        "proto-plus==1.27.1",
        "protobuf==6.33.5",
        "pydantic==2.12.5",
        "pydantic-settings==2.12.0",
        "PyJWT==2.10.1",
        "PyMySQL==1.1.0",
        "PyNaCl==1.6.2",
        "python-dotenv==1.2.1",
        "python-multipart==0.0.21",
        "pywin32==311",
        "pyzbar==0.1.9",
        "requests==2.32.5",
        "RTFDE==0.1.2.2",
        "SQLAlchemy==2.0.45",
        "sse-starlette==3.1.2",
        "starlette==0.50.0",
        "tzdata==2025.3",
        "tzlocal==5.3.1",
        "uritemplate==4.2.0",
        "uvicorn==0.40.0",
        "uv==0.9.9",
        "websockets==15.0.1"
    )

    # Write a temporary requirements file for batch install
    $reqFile = Join-Path $env:TEMP "claudetools-requirements.txt"
    $pipPackages | Out-File -FilePath $reqFile -Encoding UTF8

    Write-Info "Installing $($pipPackages.Count) Python packages (this may take several minutes)..."
    $pipOutput = python -m pip install --upgrade pip 2>&1
    $pipOutput = python -m pip install -r $reqFile 2>&1
    if ($LASTEXITCODE -eq 0) {
        Write-OK "All Python packages installed successfully"
    } else {
        # Check for partial failures
        $failLines = ($pipOutput | Select-String "ERROR:" | ForEach-Object { $_.Line })
        if ($failLines) {
            foreach ($line in $failLines) {
                Write-Err "pip: $line"
            }
        } else {
            Write-Warn "pip exited with warnings but may have succeeded. Review output above."
        }
    }

    Remove-Item $reqFile -Force -ErrorAction SilentlyContinue
}

# ---------------------------------------------------------------------------
# Phase 5: Ollama Models
# ---------------------------------------------------------------------------
function Invoke-Phase5 {
    Write-Phase 5 "Ollama Models"

    if (-not (Test-CommandExists "ollama")) {
        Refresh-PathEnv
        if (-not (Test-CommandExists "ollama")) {
            Write-Err "ollama not found. Ollama installation may have failed."
            return
        }
    }

    # Ensure Ollama service is running
    Write-Info "Ensuring Ollama service is running..."
    $ollamaProcess = Get-Process "ollama" -ErrorAction SilentlyContinue
    if (-not $ollamaProcess) {
        Write-Info "Starting Ollama service..."
        Start-Process "ollama" -ArgumentList "serve" -WindowStyle Hidden
        Start-Sleep -Seconds 3
    }

    $models = @(
        "nomic-embed-text",
        "llama3.1:8b",
        "qwen2.5-coder:7b"
    )

    foreach ($model in $models) {
        Write-Info "Pulling model: $model (this may take a while)..."
        $pullOutput = ollama pull $model 2>&1
        if ($LASTEXITCODE -eq 0) {
            Write-OK "Model $model pulled successfully"
        } else {
            $outputText = $pullOutput -join "`n"
            if ($outputText -match "up to date") {
                Write-Skip "Model $model is already up to date"
            } else {
                Write-Err "Failed to pull model $model : $outputText"
            }
        }
    }
}

# ---------------------------------------------------------------------------
# Phase 6: MCP Server Setup
# ---------------------------------------------------------------------------
function Invoke-Phase6 {
    Write-Phase 6 "MCP Server Setup (Ollama Assistant)"

    $ollamaAssistantDir = Join-Path $Script:ClaudeToolsRoot "mcp-servers\ollama-assistant"
    $venvDir = Join-Path $ollamaAssistantDir "venv"
    $venvPython = Join-Path $venvDir "Scripts\python.exe"
    $requirementsFile = Join-Path $ollamaAssistantDir "requirements.txt"

    if (-not (Test-Path $ollamaAssistantDir)) {
        Write-Err "Ollama assistant directory not found at $ollamaAssistantDir"
        return
    }

    # Create venv if it doesn't exist or is broken
    if (-not (Test-Path $venvPython)) {
        Write-Info "Creating Python virtual environment..."
        if (Test-Path $venvDir) { Remove-Item $venvDir -Recurse -Force }
        python -m venv $venvDir 2>&1 | Out-Null
        if ($LASTEXITCODE -eq 0) {
            Write-OK "Virtual environment created"
        } else {
            Write-Err "Failed to create virtual environment"
            return
        }
    } else {
        Write-Skip "Virtual environment already exists"
    }

    # Install requirements
    Write-Info "Installing MCP server dependencies..."
    if (Test-Path $requirementsFile) {
        & $venvPython -m pip install --upgrade pip 2>&1 | Out-Null
        $installOutput = & $venvPython -m pip install -r $requirementsFile 2>&1
        if ($LASTEXITCODE -eq 0) {
            Write-OK "MCP server dependencies installed"
        } else {
            Write-Err "Failed to install MCP server dependencies: $installOutput"
        }
    } else {
        # Fallback: install mcp and httpx directly
        & $venvPython -m pip install --upgrade pip 2>&1 | Out-Null
        & $venvPython -m pip install "mcp>=0.1.0" "httpx>=0.25.0" 2>&1 | Out-Null
        if ($LASTEXITCODE -eq 0) {
            Write-OK "MCP server dependencies installed (fallback)"
        } else {
            Write-Err "Failed to install MCP server dependencies"
        }
    }

    # Verify .mcp.json exists in repo
    $mcpJson = Join-Path $Script:ClaudeToolsRoot ".mcp.json"
    if (Test-Path $mcpJson) {
        Write-OK ".mcp.json configuration found in repository"
    } else {
        Write-Warn ".mcp.json not found - MCP servers will not be configured"
    }
}

# ---------------------------------------------------------------------------
# Phase 7: Claude Code Configuration
# ---------------------------------------------------------------------------
function Invoke-Phase7 {
    Write-Phase 7 "Claude Code Configuration"

    # Create directories
    foreach ($dir in @($Script:ClaudeConfigDir, $Script:ClaudeCommandsDir, $Script:MemoryDir)) {
        if (-not (Test-Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force | Out-Null
            Write-OK "Created directory: $dir"
        } else {
            Write-Skip "Directory exists: $dir"
        }
    }

    # Write settings.json
    $settingsPath = Join-Path $Script:ClaudeConfigDir "settings.json"
    $settingsContent = @'
{
  "permissions": {
    "allow": [
      "Bash(git:*)", "Bash(gh:*)", "Bash(ssh:*)", "Bash(scp:*)", "Bash(rsync:*)",
      "Bash(wsl:*)", "Bash(wsl.exe:*)", "Bash(cat:*)", "Bash(ls:*)", "Bash(find:*)",
      "Bash(grep:*)", "Bash(echo:*)", "Bash(chmod:*)", "Bash(chown:*)", "Bash(mkdir:*)",
      "Bash(rm:*)", "Bash(cp:*)", "Bash(mv:*)", "Bash(curl:*)", "Bash(wget:*)",
      "Bash(nslookup:*)", "Bash(dig:*)", "Bash(ping:*)", "Bash(python:*)", "Bash(python3:*)",
      "Bash(node:*)", "Bash(npm:*)", "Bash(npx:*)", "Bash(cargo:*)", "Bash(rustc:*)",
      "Bash(rustup:*)", "Bash(powershell:*)", "Bash(powershell.exe:*)", "Bash(pwsh:*)",
      "Bash(which:*)", "Bash(where:*)", "Bash(whoami:*)", "Bash(date:*)", "Bash(head:*)",
      "Bash(tail:*)", "Bash(less:*)", "Bash(more:*)", "Bash(diff:*)", "Bash(tar:*)",
      "Bash(unzip:*)", "Bash(zip:*)", "Bash(docker:*)", "Bash(docker-compose:*)",
      "Bash(systemctl:*)", "Bash(service:*)", "Bash(journalctl:*)", "Bash(apt:*)",
      "Bash(apt-get:*)", "Bash(brew:*)", "Bash(code:*)", "Bash(make:*)", "Bash(cmake:*)",
      "Bash(dir:*)", "Bash(wc:*)", "Bash(winget:*)", "Bash(choco:*)", "Bash(ipconfig:*)",
      "Bash(net:*)", "Bash(perl:*)", "Bash(xxd:*)", "Bash(timeout:*)", "Bash(claude:*)",
      "Bash(plink:*)", "WebFetch(domain:*)", "Skill(s)",
      "Read(//c/Users/$env:USERNAME/.claude/**)"
    ],
    "deny": [],
    "ask": []
  },
  "statusLine": {
    "type": "command",
    "command": "input=$(cat); remaining=$(echo \"$input\" | jq -r '.context_window.remaining_percentage // empty'); [ -n \"$remaining\" ] && printf \"Context: %.0f%% remaining\" \"$remaining\" || echo \"\""
  },
  "skipDangerousModePermissionPrompt": true
}
'@

    # Replace $env:USERNAME placeholder with actual username
    $settingsContent = $settingsContent -replace '\$env:USERNAME', $env:USERNAME

    Set-Content -Path $settingsPath -Value $settingsContent -Encoding UTF8 -Force
    Write-OK "settings.json written to $settingsPath"

    # Copy commands from repo to global
    $repoCommandsDir = Join-Path $Script:ClaudeToolsRoot ".claude\commands"
    if (Test-Path $repoCommandsDir) {
        $commandFiles = Get-ChildItem -Path $repoCommandsDir -File
        if ($commandFiles.Count -gt 0) {
            Copy-Item -Path "$repoCommandsDir\*" -Destination $Script:ClaudeCommandsDir -Force
            Write-OK "Copied $($commandFiles.Count) command files to $Script:ClaudeCommandsDir"
        } else {
            Write-Warn "No command files found in $repoCommandsDir"
        }
    } else {
        Write-Warn "Repo commands directory not found at $repoCommandsDir (run after Phase 3)"
    }

    # Check for archived memory to restore
    Write-Info "Checking for memory directory..."
    if (Test-Path (Join-Path $Script:MemoryDir "MEMORY.md")) {
        Write-Skip "Memory files already present"
    } else {
        Write-Warn "Memory directory is empty. If you have an archive, manually restore:"
        Write-Warn "  Copy contents to $Script:MemoryDir"
    }
}

# ---------------------------------------------------------------------------
# Phase 8: GrepAI Setup
# ---------------------------------------------------------------------------
function Invoke-Phase8 {
    Write-Phase 8 "GrepAI Setup"

    $grepaiExe = Join-Path $Script:ClaudeToolsRoot "grepai.exe"

    if (-not (Test-Path $grepaiExe)) {
        Write-Err "grepai.exe not found at $grepaiExe"
        Write-Warn "GrepAI binary should be in the repository. Ensure Phase 3 completed successfully."
        return
    }

    Write-OK "grepai.exe found at $grepaiExe"

    # Check if already initialized
    $grepaiConfig = Join-Path $Script:ClaudeToolsRoot ".grepai"
    if (Test-Path $grepaiConfig) {
        Write-Skip "GrepAI appears to already be initialized (.grepai directory exists)"
    } else {
        Write-Info "Initializing GrepAI..."
        Write-Info "This may prompt for configuration. Accept defaults for Ollama + nomic-embed-text."
        Push-Location $Script:ClaudeToolsRoot
        & $grepaiExe init 2>&1
        Pop-Location
        if ($LASTEXITCODE -eq 0) {
            Write-OK "GrepAI initialized"
        } else {
            Write-Warn "GrepAI init may require manual interaction. Run manually:"
            Write-Warn "  cd $Script:ClaudeToolsRoot && .\grepai.exe init"
        }
    }
}

# ---------------------------------------------------------------------------
# Phase 9: Verification
# ---------------------------------------------------------------------------
function Invoke-Phase9 {
    Write-Phase 9 "Verification"

    $checks = @(
        @{ Name = "Git";             Cmd = "git --version" },
        @{ Name = "Node.js";         Cmd = "node --version" },
        @{ Name = "npm";             Cmd = "npm --version" },
        @{ Name = "Python";          Cmd = "python --version" },
        @{ Name = "pip";             Cmd = "python -m pip --version" },
        @{ Name = "Ollama";          Cmd = "ollama --version" },
        @{ Name = "Claude Code CLI"; Cmd = "claude --version" }
    )

    Refresh-PathEnv

    foreach ($check in $checks) {
        try {
            $result = Invoke-Expression $check.Cmd 2>&1 | Select-Object -First 1
            if ($LASTEXITCODE -eq 0 -or $result) {
                Write-OK "$($check.Name): $result"
            } else {
                Write-Err "$($check.Name): not found or not working"
            }
        } catch {
            Write-Err "$($check.Name): $($_.Exception.Message)"
        }
    }

    # Check directories
    Write-Host ""
    Write-Info "Directory checks:"
    $dirs = @(
        $Script:ClaudeToolsRoot,
        $Script:ClaudeConfigDir,
        $Script:ClaudeCommandsDir,
        (Join-Path $Script:ClaudeToolsRoot "mcp-servers\ollama-assistant\venv")
    )
    foreach ($dir in $dirs) {
        if (Test-Path $dir) {
            Write-OK "EXISTS: $dir"
        } else {
            Write-Err "MISSING: $dir"
        }
    }

    # Check key files
    Write-Host ""
    Write-Info "File checks:"
    $files = @(
        (Join-Path $Script:ClaudeConfigDir "settings.json"),
        (Join-Path $Script:ClaudeToolsRoot ".mcp.json"),
        (Join-Path $Script:ClaudeToolsRoot "grepai.exe")
    )
    foreach ($file in $files) {
        if (Test-Path $file) {
            Write-OK "EXISTS: $file"
        } else {
            Write-Err "MISSING: $file"
        }
    }

    # Check Ollama models
    Write-Host ""
    Write-Info "Ollama model checks:"
    if (Test-CommandExists "ollama") {
        $modelList = ollama list 2>&1
        foreach ($model in @("nomic-embed-text", "llama3.1:8b", "qwen2.5-coder:7b")) {
            if ($modelList -match [regex]::Escape($model)) {
                Write-OK "Model loaded: $model"
            } else {
                Write-Warn "Model not found: $model"
            }
        }
    } else {
        Write-Warn "Cannot check Ollama models - ollama not on PATH"
    }
}

# ---------------------------------------------------------------------------
# Main Execution
# ---------------------------------------------------------------------------

Write-Host ""
Write-Host "================================================================" -ForegroundColor Cyan
Write-Host "  ClaudeTools Bootstrap / Reinstall Script" -ForegroundColor Cyan
Write-Host "  $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Cyan
Write-Host "================================================================" -ForegroundColor Cyan
Write-Host ""

# Archive mode
if ($Archive) {
    Invoke-Archive
    return
}

# Check for admin
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
if (-not $isAdmin) {
    Write-Err "This script requires administrator privileges for winget installations."
    Write-Err "Re-run from an elevated PowerShell prompt."
    exit 1
}

# Execute phases
$phases = @(
    @{ Num = 1; Func = { Invoke-Phase1 } },
    @{ Num = 2; Func = { Invoke-Phase2 } },
    @{ Num = 3; Func = { Invoke-Phase3 } },
    @{ Num = 4; Func = { Invoke-Phase4 } },
    @{ Num = 5; Func = { Invoke-Phase5 } },
    @{ Num = 6; Func = { Invoke-Phase6 } },
    @{ Num = 7; Func = { Invoke-Phase7 } },
    @{ Num = 8; Func = { Invoke-Phase8 } },
    @{ Num = 9; Func = { Invoke-Phase9 } }
)

foreach ($phase in $phases) {
    if (ShouldRunPhase $phase.Num) {
        try {
            & $phase.Func
        } catch {
            Write-Err "Phase $($phase.Num) failed with exception: $($_.Exception.Message)"
        }
    } else {
        Write-Skip "Phase $($phase.Num) skipped (by request)"
    }
}

# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
Write-Host ""
Write-Host "================================================================" -ForegroundColor Cyan
Write-Host "  Bootstrap Summary" -ForegroundColor Cyan
Write-Host "================================================================" -ForegroundColor Cyan
Write-Host ""

if ($Script:Successes.Count -gt 0) {
    Write-Host "  Successes: $($Script:Successes.Count)" -ForegroundColor Green
}
if ($Script:Skipped.Count -gt 0) {
    Write-Host "  Skipped:   $($Script:Skipped.Count)" -ForegroundColor Cyan
}
if ($Script:Warnings.Count -gt 0) {
    Write-Host "  Warnings:  $($Script:Warnings.Count)" -ForegroundColor Yellow
    foreach ($w in $Script:Warnings) {
        Write-Host "    - $w" -ForegroundColor Yellow
    }
}
if ($Script:Errors.Count -gt 0) {
    Write-Host "  Errors:    $($Script:Errors.Count)" -ForegroundColor Red
    foreach ($e in $Script:Errors) {
        Write-Host "    - $e" -ForegroundColor Red
    }
}

Write-Host ""
Write-Host "  Manual steps remaining:" -ForegroundColor Yellow
Write-Host "    1. Run 'claude' and authenticate with Anthropic API key" -ForegroundColor Yellow
Write-Host "    2. Install Claude-in-Chrome browser extension" -ForegroundColor Yellow
Write-Host "    3. Set GITHUB_PERSONAL_ACCESS_TOKEN in .mcp.json" -ForegroundColor Yellow
Write-Host "    4. Restore memory files if not already present" -ForegroundColor Yellow
Write-Host ""

if ($Script:Errors.Count -eq 0) {
    Write-Host "  [OK] Bootstrap completed successfully!" -ForegroundColor Green
} else {
    Write-Host "  [WARNING] Bootstrap completed with $($Script:Errors.Count) error(s). Review above." -ForegroundColor Yellow
}
Write-Host ""
