#!/bin/bash
# Operations CLI Template
#
# Replaces complex automation with simple, explicit commands
# Perfect for solo development with AI CLI agents
# Template: Customize for your project when copying to other repos

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
PROJECT_NAME="$(basename "$REPO_ROOT")"
CONFIG_FILE="$REPO_ROOT/devops/ops/config.yml"

# Use pyproject.toml as the primary config
PYPROJECT_CONFIG="$REPO_ROOT/pyproject.toml"
DEVOPS_CONFIG="$REPO_ROOT/config/devops.toml"

# Prefer pyproject.toml, fallback to legacy devops.toml
if [[ -f "$PYPROJECT_CONFIG" ]]; then
    DEVOPS_CONFIG="$PYPROJECT_CONFIG"
fi

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

print_status() { echo -e "${BLUE}[OPS]${NC} $1"; }
print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
print_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }

# Performance monitoring utilities
measure_time() {
    local start_time=$(date +%s.%3N)
    "$@"
    local end_time=$(date +%s.%3N)
    local duration=$(echo "$end_time - $start_time" | bc -l 2>/dev/null || echo "N/A")
    echo "⏱️ Operation completed in ${duration}s"
}

# Ensure we're in repo root
cd "$REPO_ROOT"

# Config is now handled through pyproject.toml via config_get() function

config_get() {
    local key="$1"
    if [[ -f "$DEVOPS_CONFIG" ]]; then
        python3 - "$DEVOPS_CONFIG" "$key" 2>/dev/null <<'PY'
import sys
import tomllib

path = sys.argv[1]
key = sys.argv[2]

with open(path, 'rb') as fh:
    cfg = tomllib.load(fh)

data = cfg
try:
    for part in key.split('.'):
        if isinstance(data, list):
            try:
                idx = int(part)
            except ValueError:
                raise KeyError(part)
            data = data[idx]
        else:
            data = data[part]
except (KeyError, IndexError, TypeError):
    sys.exit(0)

from pprint import pprint
if isinstance(data, (str, int, float)):
    print(data)
elif isinstance(data, (dict, list)):
    import json
    print(json.dumps(data))
PY
    fi
}

# Get targets from config or default
get_targets() {
    local parsed_targets

    local default_target=""
    if [[ -f "$DEVOPS_CONFIG" ]]; then
        default_target=$(config_get "deploy.target")
    fi

    if [[ -z "$default_target" ]] && [[ -f "$CONFIG_FILE" ]]; then
        parsed_targets=$(python3 - "$CONFIG_FILE" 2>/dev/null <<'PY'
import pathlib
import sys

config_path = pathlib.Path(sys.argv[1])
targets = []
current = None

for raw_line in config_path.read_text().splitlines():
    line = raw_line.rstrip()
    stripped = line.strip()

    if not stripped or stripped.startswith('#'):
        continue

    if not line.startswith(' '):
        current = stripped.rstrip(':')
        continue

    if current == 'targets' and stripped.startswith('- '):
        targets.append(stripped[2:].strip())

if targets:
    print('\n'.join(targets))
PY
        )
        parsed_targets=$(echo "$parsed_targets" | sed '/^$/d')
    fi

    if [[ -n "$default_target" ]]; then
        echo "$default_target"
    elif [[ -n "$parsed_targets" ]]; then
        echo "$parsed_targets"
    else
        echo "$HOME/deploy/$PROJECT_NAME"
    fi
}

# Activate virtual environment
activate_venv() {
    local auto_bootstrap
    auto_bootstrap=$(config_get "env.auto_bootstrap")
    [[ -z "$auto_bootstrap" ]] && auto_bootstrap="true"

    if [[ -f ".venv/bin/activate" ]]; then
        source .venv/bin/activate
        return 0
    elif [[ -f "venv/bin/activate" ]]; then
        source venv/bin/activate
        return 0
    fi

    if [[ "$auto_bootstrap" =~ ^(true|1|yes)$ ]]; then
        print_warning "No virtual environment found - creating .venv (disable via env.auto_bootstrap=false)"
        python3 -m venv .venv
        source .venv/bin/activate
        if [[ -f requirements-dev.txt ]]; then
            pip install -r requirements-dev.txt >/dev/null 2>&1 || true
        fi
        if [[ -f requirements.txt ]]; then
            pip install -r requirements.txt >/dev/null 2>&1 || true
        fi
        return 0
    fi

    print_warning "No virtual environment found. Install dependencies manually or enable env.auto_bootstrap in config/devops.toml"
    return 1
}

# Commands
cmd_setup() {
    local target="${1:-$HOME/deploy/project}"
    local auto_release="${2:-false}"

    print_status "Setting up project operations"
    print_status "Target: $target"

    # Create config
    mkdir -p "$(dirname "$CONFIG_FILE")"
    cat > "$CONFIG_FILE" << EOF
# Project Operations Config
# Template: Customize for your project
versioning:
  strategy: conventional_commits
  source: pyproject.toml

targets:
  - $target

release:
  changelog: true
  tag_prefix: v

qa:
  lint: true
  typecheck: true
  tests: "not slow"

env:
  wsl_check: true

hooks:
  auto_sync: $auto_release
EOF

    print_success "Config created: $CONFIG_FILE"
    print_status "Run: ops qa → ops build → ops verify-prod → ops release"
}

cmd_qa() {
    local test_type="all"

    while [[ $# -gt 0 ]]; do
        case $1 in
            --backend) test_type="backend"; shift ;;
            --frontend) test_type="frontend"; shift ;;
            --all) test_type="all"; shift ;;
            *) break ;;
        esac
    done

    print_status "Running quality assurance checks ($test_type)"

    # Backend QA
    if [[ "$test_type" == "backend" ]] || [[ "$test_type" == "all" ]]; then
        activate_venv

        local test_cmd
        test_cmd=$(config_get "package.test_command")

        if [[ -n "$test_cmd" ]]; then
            echo "🧪 Running backend tests via config: $test_cmd"
            eval "$test_cmd" || true
        else
            echo "🧹 Linting and fixing backend..."
            ruff check src/ --fix || true

            echo "🎨 Formatting backend..."
            black src/ || true

            echo "🔍 Type checking backend..."
            mypy src/ || true

            echo "🧪 Running backend tests..."
            if [[ -d "tests/backend" ]]; then
                echo "   Using standardized tests/backend/ structure..."
                python3 run.py -m pytest tests/backend/ -m "not slow" || true
            elif [[ -d "tests/unit" ]] && [[ -d "tests/integration" ]]; then
                echo "   Using legacy tests/unit + tests/integration structure..."
                python3 run.py -m pytest tests/unit/ -v || true
                python3 run.py -m pytest tests/integration/ -m "not slow" -v || true
            else
                echo "   Running all tests (fallback)..."
                python3 run.py -m pytest -m "not slow" || true
            fi
        fi
    fi

    # Frontend QA
    if [[ "$test_type" == "frontend" ]] || [[ "$test_type" == "all" ]]; then
        if [[ -d "tests/frontend" ]] && [[ -f "package.json" ]]; then
            echo "🧹 Linting frontend..."
            npm run lint:frontend 2>/dev/null || echo "⚠️ Frontend linting not configured"

            echo "🔍 Type checking frontend..."
            npm run typecheck:frontend 2>/dev/null || echo "⚠️ Frontend type checking not configured"

            echo "🎭 Running frontend tests..."
            npm run test:frontend:smoke 2>/dev/null || npm run test:frontend 2>/dev/null || echo "⚠️ Frontend tests not configured"
        else
            echo "📝 Frontend tests directory not found - skipping frontend QA"
        fi
    fi

    print_success "QA complete ($test_type)"
}

cmd_build() {
    local target=""
    local force=false

    while [[ $# -gt 0 ]]; do
        case $1 in
            --target)
                target="$2"
                shift 2
                ;;
            --force)
                force=true
                shift
                ;;
            *)
                print_error "Unknown option: $1"
                return 1
                ;;
        esac
    done

    if [[ -z "$target" ]]; then
        target=$(get_targets | head -1)
    fi

    print_status "Building production version to: $target"

    # Use existing build script
    if [[ -f "devops/deploy/commands/build-production.sh" ]]; then
        local args=("$target")
        [[ "$force" == true ]] && args+=(--force)
        ./devops/deploy/commands/build-production.sh "${args[@]}"
    else
        # Fallback simple build
        mkdir -p "$target"
        activate_venv || true

        rsync -a src/ "$target/src/"
        [[ -d docs ]] && rsync -a docs/ "$target/docs/"
        [[ -f README.md ]] && cp README.md "$target/"
        [[ -f VERSION ]] && cp VERSION "$target/"
        [[ -f requirements.txt ]] && cp requirements.txt "$target/"
        [[ -f install.sh ]] && cp install.sh "$target/"

        local cli_name
        cli_name=$(config_get "package.manifest.cli")
        [[ -z "$cli_name" ]] && cli_name="$PROJECT_NAME"

        if [[ -f "$cli_name" ]]; then
            cp "$cli_name" "$target/$cli_name"
        elif [[ -f "$PROJECT_NAME" ]]; then
            cp "$PROJECT_NAME" "$target/$PROJECT_NAME"
            cli_name="$PROJECT_NAME"
        fi

        chmod +x "$target/install.sh" "$target/$cli_name" 2>/dev/null || true
    fi

    print_success "Build complete: $target"
}

cmd_verify_prod() {
    local target="${1:-$(get_targets | head -1)}"

    print_status "Verifying production build: $target"

    if [[ ! -d "$target" ]]; then
        print_error "Target directory not found: $target"
        return 1
    fi

    cd "$target"

    echo "1️⃣ Testing install script..."
    test -x install.sh || { print_error "install.sh not executable"; return 1; }

    local cli_name
    cli_name=$(config_get "package.manifest.cli")
    [[ -z "$cli_name" ]] && cli_name="$PROJECT_NAME"

    echo "2️⃣ Testing CLI wrapper..."
    test -x "$cli_name" || { print_error "$cli_name not executable"; return 1; }

    echo "3️⃣ Testing help command..."
    ./"$cli_name" --help >/dev/null || { print_error "CLI help failed"; return 1; }

    echo "4️⃣ Testing source structure..."
    test -d src/ || { print_error "src/ directory missing"; return 1; }

    echo "5️⃣ Running basic tests..."
    if [[ -f ".venv/bin/activate" ]]; then
        source .venv/bin/activate
        python3 -c "import importlib, sys; sys.path.append('src'); importlib.import_module('$PROJECT_NAME')" 2>/dev/null || \
        python3 -c "import sys; sys.path.append('src'); import agentswarm.cli.main" 2>/dev/null || \
        python3 -c "import sys; sys.path.append('src'); import cli.main" || { print_error "Import test failed"; return 1; }
    fi

    cd "$REPO_ROOT"
    print_success "Production verification passed"
}

cmd_sync() {
    print_status "Syncing to all configured targets"

    while IFS= read -r target; do
        if [[ -n "$target" ]]; then
            print_status "Syncing to: $target"
            cmd_build --target "$target" --force
        fi
    done <<< "$(get_targets)"

    print_success "Sync complete"
}

cmd_release() {
    local bump_type="${1:-patch}"

    print_status "Creating $bump_type release"
    activate_venv

    # Get current version from pyproject.toml
    local current_version=$(grep '^version = ' pyproject.toml | sed 's/version = "\(.*\)"/\1/')
    print_status "Current version: $current_version"

    # Calculate new version
    IFS='.' read -ra VERSION_PARTS <<< "$current_version"
    local major=${VERSION_PARTS[0]:-0}
    local minor=${VERSION_PARTS[1]:-0}
    local patch=${VERSION_PARTS[2]:-0}

    case "$bump_type" in
        major)
            major=$((major + 1))
            minor=0
            patch=0
            ;;
        minor)
            minor=$((minor + 1))
            patch=0
            ;;
        patch)
            patch=$((patch + 1))
            ;;
        *)
            print_error "Invalid bump type: $bump_type (use: major, minor, patch)"
            return 1
            ;;
    esac

    local new_version="$major.$minor.$patch"
    print_status "New version: $new_version"

    # Update pyproject.toml
    sed -i "s/version = \".*\"/version = \"$new_version\"/" pyproject.toml

    # Commit version bump
    git add pyproject.toml
    git commit -m "bump: version $new_version"

    # Create and push tag
    git tag "v$new_version"
    git push origin main
    git push origin "v$new_version"

    print_success "Release v$new_version created and pushed"
    print_status "GitHub Actions will build and publish the release"
}

cmd_security() {
    local scan_type="all"

    while [[ $# -gt 0 ]]; do
        case $1 in
            --dependencies) scan_type="dependencies"; shift ;;
            --secrets) scan_type="secrets"; shift ;;
            --code) scan_type="code"; shift ;;
            --all) scan_type="all"; shift ;;
            *) break ;;
        esac
    done

    print_status "Running security scans ($scan_type)"

    # Dependencies security scan
    if [[ "$scan_type" == "dependencies" ]] || [[ "$scan_type" == "all" ]]; then
        echo "🔒 Scanning dependencies for vulnerabilities..."
        
        # Python dependencies
        if [[ -f "pyproject.toml" ]] || [[ -f "requirements.txt" ]]; then
            activate_venv
            if command -v safety >/dev/null 2>&1; then
                safety check || print_warning "Some dependency vulnerabilities found"
            else
                print_info "Install 'safety' for dependency vulnerability scanning: pip install safety"
            fi
        fi
        
        # Node dependencies
        if [[ -f "package.json" ]]; then
            if command -v npm >/dev/null 2>&1; then
                npm audit --audit-level moderate || print_warning "Some npm vulnerabilities found"
            fi
        fi
    fi

    # Secrets detection
    if [[ "$scan_type" == "secrets" ]] || [[ "$scan_type" == "all" ]]; then
        echo "🔍 Scanning for exposed secrets..."
        
        # Check for common secret patterns
        local secret_patterns=(
            "password\s*=\s*['\"][^'\"]*['\"]"
            "api_key\s*=\s*['\"][^'\"]*['\"]"
            "secret\s*=\s*['\"][^'\"]*['\"]"
            "token\s*=\s*['\"][^'\"]*['\"]"
            "AKIA[0-9A-Z]{16}"  # AWS Access Key
            "sk_live_[0-9a-zA-Z]{24}"  # Stripe Live Key
        )
        
        local secrets_found=false
        for pattern in "${secret_patterns[@]}"; do
            if grep -r -E "$pattern" . --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=venv --exclude="*.log" >/dev/null 2>&1; then
                secrets_found=true
                print_warning "Potential secret pattern found: $pattern"
            fi
        done
        
        if [[ "$secrets_found" == false ]]; then
            print_success "No obvious secret patterns detected"
        fi
        
        # Check .env files are gitignored
        if [[ -f ".env" ]] && ! grep -q "\.env" .gitignore 2>/dev/null; then
            print_warning ".env file exists but not in .gitignore"
        fi
    fi

    # Code security scan
    if [[ "$scan_type" == "code" ]] || [[ "$scan_type" == "all" ]]; then
        echo "🛡️ Scanning code for security issues..."
        
        # Python security with bandit
        if [[ -d "src" ]] && command -v bandit >/dev/null 2>&1; then
            bandit -r src/ -f json -o security_report.json || print_warning "Some code security issues found"
            if [[ -f "security_report.json" ]]; then
                local issues=$(jq '.results | length' security_report.json 2>/dev/null || echo "0")
                print_info "Found $issues potential security issues (see security_report.json)"
            fi
        elif [[ -d "src" ]]; then
            print_info "Install 'bandit' for Python code security scanning: pip install bandit"
        fi
        
        # Check file permissions
        local suspicious_files=$(find . -type f \( -perm -4000 -o -perm -2000 \) 2>/dev/null | grep -v ".git" || true)
        if [[ -n "$suspicious_files" ]]; then
            print_warning "Files with suspicious permissions found:"
            echo "$suspicious_files"
        fi
    fi

    print_success "Security scan completed"
}

cmd_rollback() {
    local target_version="$1"
    local target_dir="${2:-$(get_targets | head -1)}"

    if [[ -z "$target_version" ]]; then
        print_error "Usage: ops rollback <version> [target_dir]"
        print_status "Available versions:"
        git tag --list "v*" --sort=-version:refname | head -10
        return 1
    fi

    # Validate version exists
    if ! git tag --list | grep -q "^${target_version}$"; then
        if ! git tag --list | grep -q "^v${target_version}$"; then
            print_error "Version $target_version not found"
            print_status "Available versions:"
            git tag --list "v*" --sort=-version:refname | head -10
            return 1
        else
            target_version="v${target_version}"
        fi
    fi

    print_status "Rolling back to version: $target_version"
    print_warning "This will:"
    print_warning "  - Checkout the specified version"
    print_warning "  - Rebuild to target directory: $target_dir"
    print_warning "  - Update production deployment"

    read -p "Continue with rollback? (y/N): " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        print_status "Rollback cancelled"
        return 0
    fi

    # Stash any uncommitted changes
    if [[ -n "$(git status --porcelain)" ]]; then
        print_status "Stashing uncommitted changes..."
        git stash push -m "Pre-rollback stash"
    fi

    # Checkout the target version
    print_status "Checking out $target_version..."
    git checkout "$target_version"

    # Rebuild to target directory
    print_status "Rebuilding to $target_dir..."
    cmd_build --target "$target_dir" --force

    # Verify the rollback
    print_status "Verifying rollback..."
    cmd_verify_prod "$target_dir"

    print_success "Rollback to $target_version complete"
    print_status "Production deployment updated: $target_dir"

    # Show rollback info
    echo ""
    echo "📋 Rollback Summary:"
    echo "   Version: $target_version"
    echo "   Target: $target_dir"
    echo "   Date: $(git log -1 --format=%cd --date=short)"
    echo "   Commit: $(git log -1 --format=%h)"

    # Check if we stashed changes
    if git stash list | grep -q "Pre-rollback stash"; then
        print_warning "Uncommitted changes were stashed"
        print_status "To restore: git stash pop"
    fi
}

cmd_status() {
    print_status "SignalHire Agent Operations Status"

    echo "📁 Repository: $REPO_ROOT"
    echo "⚙️  Config: $([ -f "$CONFIG_FILE" ] && echo "✅ $CONFIG_FILE" || echo "❌ Not found")"

    if [[ -f "pyproject.toml" ]]; then
        local version=$(python3 -c "import toml; print(toml.load('pyproject.toml')['project']['version'])" 2>/dev/null || echo "unknown")
        echo "🏷️  Version: $version"
    fi

    local last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "none")
    echo "🏷️  Last tag: $last_tag"

    echo "🎯 Targets:"
    while IFS= read -r target; do
        if [[ -n "$target" ]]; then
            local status="❌"
            [[ -d "$target" ]] && status="✅"
            echo "   $status $target"
        fi
    done <<< "$(get_targets)"

    echo "🐍 Environment:"
    if [[ -f ".venv/bin/activate" ]]; then
        echo "   ✅ .venv virtual environment"
    elif [[ -f "venv/bin/activate" ]]; then
        echo "   ✅ venv virtual environment"
    else
        echo "   ❌ No virtual environment found"
    fi
}

cmd_env_doctor() {
    print_status "Environment diagnostics"

    echo "🐍 Python environment:"
    echo "   Python path: $(which python3)"
    echo "   Python version: $(python3 --version)"

    if grep -q microsoft /proc/version 2>/dev/null; then
        echo "🪟 WSL detected"

        # Check .env file accessibility
        if [[ -f ".env" ]]; then
            echo "   ✅ .env file found"
            if python3 -c "from dotenv import load_dotenv; load_dotenv()" 2>/dev/null; then
                echo "   ✅ .env file loadable"
            else
                print_warning ".env file exists but not loadable - install python-dotenv"
                echo "   Fix: pip install python-dotenv"
            fi
        else
            print_warning "No .env file found"
            echo "   Create: cp .env.example .env"
        fi

        # Check for Windows/WSL path issues
        if echo "$PATH" | grep -q "/mnt/c/"; then
            print_warning "Windows paths detected in WSL PATH"
            echo "   This can cause environment issues"
            echo "   Consider using WSL-native Python: sudo apt install python3-venv"
        fi
    fi

    echo "📦 Dependencies:"
    activate_venv >/dev/null 2>&1
    local deps_ok=true

    for dep in ruff mypy black pytest; do
        if command -v "$dep" >/dev/null 2>&1; then
            echo "   ✅ $dep"
        else
            echo "   ❌ $dep"
            deps_ok=false
        fi
    done

    if [[ "$deps_ok" == false ]]; then
        print_warning "Missing dependencies detected"
        echo "   Fix: pip install -e .[dev]"
    fi

    print_success "Environment check complete"
}

cmd_hooks() {
    local action="$1"

    case "$action" in
        install)
            print_status "Installing git hooks for auto-sync"
            cat > .git/hooks/post-commit << 'EOF'
#!/bin/bash
# Auto-sync after commits (optional)
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
if [[ -x "$REPO_ROOT/scripts/ops" ]]; then
    "$REPO_ROOT/scripts/ops" sync >/dev/null 2>&1 &
fi
EOF
            chmod +x .git/hooks/post-commit
            print_success "Git hooks installed (auto-sync enabled)"
            ;;
        remove)
            print_status "Removing git hooks"
            rm -f .git/hooks/post-commit
            print_success "Git hooks removed (auto-sync disabled)"
            ;;
        *)
            print_error "Usage: ops hooks [install|remove]"
            return 1
            ;;
    esac
}

# Main command dispatch
case "${1:-help}" in
    setup)
        shift
        cmd_setup "$@"
        ;;
    qa)
        cmd_qa
        ;;
    security)
        shift
        cmd_security "$@"
        ;;
    build)
        shift
        cmd_build "$@"
        ;;
    verify-prod)
        cmd_verify_prod "$2"
        ;;
    sync)
        cmd_sync
        ;;
    release)
        cmd_release "$2"
        ;;
    rollback)
        cmd_rollback "$2" "$3"
        ;;
    status)
        cmd_status
        ;;
    env)
        case "$2" in
            doctor)
                cmd_env_doctor
                ;;
            *)
                print_error "Usage: ops env doctor"
                exit 1
                ;;
        esac
        ;;
    hooks)
        cmd_hooks "$2"
        ;;
    help|--help|-h)
        cat << EOF
Project Operations CLI (Template)

USAGE:
    ops <command> [options]

COMMANDS:
    setup [target]           Setup operations config and target directory
    qa [--backend|--frontend|--all]  Run quality checks (lint, format, typecheck, tests)
    security [--dependencies|--secrets|--code|--all]  Run security scans
    build --target PATH      Build production version to target
    verify-prod [target]     Verify production build works correctly
    sync                     Sync to all configured targets
    release [patch|minor|major]  Create and push new release
    rollback <version> [target]   Rollback to previous version
    status                   Show current status and configuration
    env doctor              Check environment and WSL compatibility
    hooks [install|remove]   Manage auto-sync git hooks (optional)

EXAMPLES:
    ops setup ~/deploy/your-project    # Customize path for your project
    ops qa
    ops security --all                 # Run comprehensive security scans
    ops build --target ~/deploy/your-project --force
    ops verify-prod
    ops release minor
    ops rollback v1.2.3
    ops status
    ops env doctor

WORKFLOW:
    Daily: ops qa → ops build → ops verify-prod
    Release: ops release [patch|minor|major]
    Sync: ops sync (or enable with ops hooks install)

TEMPLATE NOTE:
    This ops system is designed as a template. When copying to other projects,
    customize the QA commands, build scripts, and target paths for your specific stack.
EOF
        ;;
    *)
        print_error "Unknown command: $1"
        print_status "Run 'ops help' for usage information"
        exit 1
        ;;
esac
