#!/usr/bin/env python3
"""
Workspace Manager API Server
Port: 9004
Provides REST API for monitoring disk usage, executing cleanups, and managing backups
"""

from flask import Flask, jsonify, request
from flask_cors import CORS
import subprocess
import json
import os
import re
from datetime import datetime

app = Flask(__name__)
CORS(app)

# Constants
HOME = os.path.expanduser('~')
ARCHIVE_DIR = os.path.join(HOME, 'Archive')
ICLOUD_PATH = os.path.join(HOME, 'Library/Mobile Documents/com~apple~CloudDocs')

# ============================================================================
# UTILITY FUNCTIONS
# ============================================================================

def get_dir_size(path, max_depth=5, current_depth=0, visited=None):
    """
    Calcula tamanho de diretório recursivamente com proteção
    """
    if visited is None:
        visited = set()

    if current_depth >= max_depth:
        return 0

    try:
        real_path = os.path.realpath(path)
        if real_path in visited:
            return 0
        visited.add(real_path)

        if not os.path.exists(path):
            return 0

        if os.path.isfile(path):
            return os.path.getsize(path)

        total = 0
        for entry in os.scandir(path):
            if entry.name == 'Archive':  # Skip Archive
                continue
            try:
                if entry.is_symlink():
                    continue
                if entry.is_file():
                    total += entry.stat().st_size
                elif entry.is_dir():
                    total += get_dir_size(entry.path, max_depth, current_depth + 1, visited)
            except (PermissionError, OSError):
                continue
        return total
    except (PermissionError, OSError):
        return 0

def format_size(bytes_size):
    """
    Converte bytes para formato legível
    """
    for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
        if bytes_size < 1024.0:
            return f"{bytes_size:.2f} {unit}"
        bytes_size /= 1024.0
    return f"{bytes_size:.2f} PB"

def get_last_cleanup_date():
    """
    Lê última data de cleanup do CLEANUP-LOG.md
    """
    try:
        log_path = os.path.join(HOME, 'CLEANUP-LOG.md')
        if os.path.exists(log_path):
            with open(log_path, 'r') as f:
                content = f.read()
                # Procurar por data no formato "**Cleanup executado em:** 2025-12-13"
                match = re.search(r'\*\*Cleanup executado em:\*\* (\d{4}-\d{2}-\d{2})', content)
                if match:
                    return match.group(1)
        return None
    except:
        return None

# ============================================================================
# HEALTH & INFO ENDPOINTS
# ============================================================================

@app.route('/health')
def health():
    """Health check endpoint"""
    return jsonify({
        'status': 'ok',
        'service': 'workspace-manager-api',
        'timestamp': datetime.now().isoformat()
    })

@app.route('/')
def index():
    """Root endpoint with API info"""
    return jsonify({
        'service': 'Workspace Manager API',
        'version': '1.0.0',
        'port': 9004,
        'endpoints': [
            '/health',
            '/api/disk/overview',
            '/api/disk/cache',
            '/api/cleanup/cache',
            '/api/cleanup/monthly',
            '/api/icloud/status',
            '/api/icloud/backups',
            '/api/projects/overview',
            '/api/stats/summary'
        ],
        'timestamp': datetime.now().isoformat()
    })

# ============================================================================
# DISK MONITORING ENDPOINTS
# ============================================================================

@app.route('/api/disk/overview')
def disk_overview():
    """
    Retorna visão geral do uso de disco
    """
    try:
        directories = {
            'archive': os.path.join(HOME, 'Archive'),
            'apps': os.path.join(HOME, 'Apps'),
            'web': os.path.join(HOME, 'Web'),
            'projects': os.path.join(HOME, 'Projects'),
            'services': os.path.join(HOME, 'Services'),
            'scripts': os.path.join(HOME, 'Scripts')
        }

        data = {}
        for name, path in directories.items():
            size_bytes = get_dir_size(path) if os.path.exists(path) else 0
            data[name] = {
                'path': path,
                'size_bytes': size_bytes,
                'size_human': format_size(size_bytes),
                'exists': os.path.exists(path)
            }

        return jsonify({
            'status': 'ok',
            'timestamp': datetime.now().isoformat(),
            'data': data
        })
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/api/disk/cache')
def disk_cache():
    """
    Retorna tamanho de caches e build artifacts
    """
    try:
        # Get pip cache dir
        pip_cache_result = subprocess.run(
            ['pip3', 'cache', 'dir'],
            capture_output=True,
            text=True,
            timeout=10
        )
        pip_cache_dir = pip_cache_result.stdout.strip() if pip_cache_result.returncode == 0 else ''

        cache_dirs = {
            'xcode_derived_data': os.path.join(HOME, 'Library/Developer/Xcode/DerivedData'),
            'system_cache': os.path.join(HOME, '.cache'),
            'npm_cache': os.path.join(HOME, '.npm'),
            'pip_cache': pip_cache_dir
        }

        data = {}
        for name, path in cache_dirs.items():
            if path and os.path.exists(path):
                size_bytes = get_dir_size(path)
                data[name] = {
                    'path': path,
                    'size_bytes': size_bytes,
                    'size_human': format_size(size_bytes),
                    'can_delete': True
                }

        return jsonify({
            'status': 'ok',
            'timestamp': datetime.now().isoformat(),
            'data': data
        })
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

# ============================================================================
# CLEANUP OPERATION ENDPOINTS
# ============================================================================

@app.route('/api/cleanup/cache', methods=['POST'])
def cleanup_cache():
    """
    Executa limpeza de cache
    Aceita: {'targets': ['xcode', 'npm', 'pip', 'system']}
    """
    try:
        data = request.json or {}
        targets = data.get('targets', [])

        results = {}
        space_freed = 0

        if 'xcode' in targets:
            xcode_path = os.path.join(HOME, 'Library/Developer/Xcode/DerivedData')
            before = get_dir_size(xcode_path) if os.path.exists(xcode_path) else 0
            if before > 0:
                subprocess.run(['rm', '-rf', xcode_path], timeout=60)
                space_freed += before
                results['xcode'] = {
                    'freed_bytes': before,
                    'freed_human': format_size(before)
                }

        if 'npm' in targets:
            result = subprocess.run(
                ['npm', 'cache', 'clean', '--force'],
                capture_output=True,
                text=True,
                timeout=60
            )
            results['npm'] = {
                'success': result.returncode == 0,
                'message': 'NPM cache cleaned' if result.returncode == 0 else result.stderr
            }

        if 'pip' in targets:
            result = subprocess.run(
                ['pip3', 'cache', 'purge'],
                capture_output=True,
                text=True,
                timeout=60
            )
            results['pip'] = {
                'success': result.returncode == 0,
                'message': 'Pip cache purged' if result.returncode == 0 else result.stderr
            }

        if 'system' in targets:
            cache_path = os.path.join(HOME, '.cache')
            before = get_dir_size(cache_path) if os.path.exists(cache_path) else 0
            if before > 0:
                subprocess.run(['rm', '-rf', cache_path], timeout=60)
                space_freed += before
                results['system'] = {
                    'freed_bytes': before,
                    'freed_human': format_size(before)
                }

        return jsonify({
            'status': 'ok',
            'timestamp': datetime.now().isoformat(),
            'results': results,
            'total_freed_bytes': space_freed,
            'total_freed_human': format_size(space_freed)
        })
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/api/cleanup/monthly', methods=['POST'])
def cleanup_monthly():
    """
    Executa monthly-cleanup.sh
    Aceita: {'dry_run': bool}
    """
    try:
        data = request.json or {}
        dry_run = data.get('dry_run', False)

        script_path = os.path.join(HOME, 'Scripts/system/monthly-cleanup.sh')

        if not os.path.exists(script_path):
            return jsonify({
                'status': 'error',
                'message': f'Script not found: {script_path}'
            }), 404

        cmd = [script_path]
        if dry_run:
            cmd.append('--dry-run')

        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            timeout=300
        )

        return jsonify({
            'status': 'ok' if result.returncode == 0 else 'error',
            'timestamp': datetime.now().isoformat(),
            'dry_run': dry_run,
            'output': result.stdout,
            'error': result.stderr if result.returncode != 0 else None
        })
    except subprocess.TimeoutExpired:
        return jsonify({
            'status': 'error',
            'message': 'Cleanup script timed out after 5 minutes'
        }), 500
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

# ============================================================================
# iCLOUD BACKUP MANAGEMENT ENDPOINTS
# ============================================================================

@app.route('/api/icloud/status')
def icloud_status():
    """
    Retorna status de sincronização do iCloud
    """
    try:
        # Verificar se iCloud está configurado
        account_id = None
        try:
            result = subprocess.run(
                ['defaults', 'read', 'MobileMeAccounts', 'Accounts'],
                capture_output=True,
                text=True,
                timeout=10
            )
            if 'AccountID' in result.stdout:
                for line in result.stdout.split('\n'):
                    if 'AccountID' in line:
                        account_id = line.split('=')[1].strip().strip(';').strip('"')
        except:
            pass

        # Verificar status de sync do brctl
        sync_active = False
        try:
            brctl_result = subprocess.run(
                ['brctl', 'status'],
                capture_output=True,
                text=True,
                timeout=10
            )
            sync_active = 'containers matching' in brctl_result.stdout
        except:
            pass

        # Tamanho do diretório de backups
        backups_path = os.path.join(ICLOUD_PATH, 'Backups/Workspace')
        backups_size = 0
        if os.path.exists(backups_path):
            backups_size = get_dir_size(backups_path)

        return jsonify({
            'status': 'ok',
            'timestamp': datetime.now().isoformat(),
            'data': {
                'account_id': account_id,
                'sync_active': sync_active,
                'icloud_path': ICLOUD_PATH,
                'backups_path': backups_path,
                'backups_size_bytes': backups_size,
                'backups_size_human': format_size(backups_size)
            }
        })
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/api/icloud/backups')
def icloud_backups():
    """
    Lista backups no iCloud Drive
    """
    try:
        backups_path = os.path.join(ICLOUD_PATH, 'Backups/Workspace')

        if not os.path.exists(backups_path):
            return jsonify({
                'status': 'ok',
                'timestamp': datetime.now().isoformat(),
                'data': {'backups': [], 'total': 0}
            })

        backups = []
        for item in os.listdir(backups_path):
            item_path = os.path.join(backups_path, item)
            if os.path.isdir(item_path):
                stat = os.stat(item_path)
                size_bytes = get_dir_size(item_path)
                backups.append({
                    'name': item,
                    'path': item_path,
                    'size_bytes': size_bytes,
                    'size_human': format_size(size_bytes),
                    'modified': datetime.fromtimestamp(stat.st_mtime).isoformat()
                })

        return jsonify({
            'status': 'ok',
            'timestamp': datetime.now().isoformat(),
            'data': {
                'backups': backups,
                'total': len(backups)
            }
        })
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

# ============================================================================
# PROJECT DASHBOARD ENDPOINTS
# ============================================================================

@app.route('/api/projects/overview')
def projects_overview():
    """
    Retorna visão geral dos projetos
    """
    try:
        projects_path = os.path.join(HOME, 'Projects')

        categories = {
            'core': os.path.join(projects_path, 'core'),
            'tools': os.path.join(projects_path, 'tools'),
            'experiments': os.path.join(projects_path, 'experiments')
        }

        data = {}
        for category, path in categories.items():
            if not os.path.exists(path):
                continue

            projects = []
            for project_name in os.listdir(path):
                project_path = os.path.join(path, project_name)
                if not os.path.isdir(project_path):
                    continue

                try:
                    stat = os.stat(project_path)
                    size_bytes = get_dir_size(project_path, max_depth=3)
                    projects.append({
                        'name': project_name,
                        'path': project_path,
                        'size_bytes': size_bytes,
                        'size_human': format_size(size_bytes),
                        'modified': datetime.fromtimestamp(stat.st_mtime).isoformat(),
                        'has_git': os.path.exists(os.path.join(project_path, '.git')),
                        'has_package_json': os.path.exists(os.path.join(project_path, 'package.json')),
                        'has_requirements': os.path.exists(os.path.join(project_path, 'requirements.txt'))
                    })
                except (PermissionError, OSError):
                    continue

            data[category] = {
                'projects': sorted(projects, key=lambda x: x['modified'], reverse=True),
                'count': len(projects)
            }

        return jsonify({
            'status': 'ok',
            'timestamp': datetime.now().isoformat(),
            'data': data
        })
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

# ============================================================================
# HEALTH & STATS ENDPOINTS
# ============================================================================

@app.route('/api/open-xcode', methods=['POST'])
def open_xcode():
    """
    Abre projeto no Xcode
    Aceita: {'path': '/Users/neog/Apps/iOS/AppName'}
    """
    try:
        data = request.json or {}
        project_path = data.get('path', '')

        if not project_path:
            return jsonify({'status': 'error', 'message': 'Path is required'}), 400

        # Validate path is under allowed directories
        allowed_prefixes = [
            os.path.join(HOME, 'Apps/iOS'),
            os.path.join(HOME, 'Apps/macOS'),
            os.path.join(HOME, 'Projects')
        ]

        is_allowed = any(project_path.startswith(prefix) for prefix in allowed_prefixes)
        if not is_allowed:
            return jsonify({'status': 'error', 'message': 'Path not allowed'}), 403

        if not os.path.exists(project_path):
            return jsonify({'status': 'error', 'message': 'Path not found'}), 404

        # Find .xcodeproj or .xcworkspace
        xcodeproj = None
        xcworkspace = None

        for item in os.listdir(project_path):
            if item.endswith('.xcworkspace') and not item.startswith('.'):
                xcworkspace = os.path.join(project_path, item)
            elif item.endswith('.xcodeproj'):
                xcodeproj = os.path.join(project_path, item)

        # Prefer xcworkspace over xcodeproj
        target = xcworkspace or xcodeproj or project_path

        # Open in Xcode
        result = subprocess.run(
            ['open', '-a', 'Xcode', target],
            capture_output=True,
            text=True,
            timeout=10
        )

        if result.returncode == 0:
            return jsonify({
                'status': 'ok',
                'message': f'Opened {os.path.basename(target)} in Xcode',
                'target': target
            })
        else:
            return jsonify({
                'status': 'error',
                'message': result.stderr or 'Failed to open Xcode'
            }), 500

    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

def get_project_briefing(project_path):
    """
    Extract briefing information from CLAUDE.md or README.md
    Returns summary, features list, and metadata
    """
    briefing = {
        'summary': None,
        'features': [],
        'platform': None,
        'bundle_id': None,
        'has_docs': False
    }

    # Try CLAUDE.md first, then README.md
    doc_files = ['CLAUDE.md', 'README.md', 'readme.md']
    content = None

    for doc_file in doc_files:
        doc_path = os.path.join(project_path, doc_file)
        if os.path.exists(doc_path):
            try:
                with open(doc_path, 'r', encoding='utf-8') as f:
                    content = f.read()
                    briefing['has_docs'] = True
                    break
            except:
                continue

    if content:
        lines = content.split('\n')

        # Extract first paragraph as summary (skip title)
        in_summary = False
        summary_lines = []
        for line in lines:
            stripped = line.strip()
            if stripped.startswith('#'):
                if in_summary:
                    break
                in_summary = True
                continue
            if in_summary and stripped:
                if stripped.startswith('##') or stripped.startswith('```'):
                    break
                summary_lines.append(stripped)
                if len(summary_lines) >= 3:
                    break

        if summary_lines:
            briefing['summary'] = ' '.join(summary_lines)[:300]

        # Extract features from bullet points under "Features" or "App Features"
        in_features = False
        for line in lines:
            stripped = line.strip()
            if '## ' in line and ('feature' in line.lower() or 'overview' in line.lower()):
                in_features = True
                continue
            if in_features:
                if stripped.startswith('## '):
                    break
                if stripped.startswith('- ') or stripped.startswith('* '):
                    feature = stripped[2:].strip()
                    if feature and len(briefing['features']) < 5:
                        briefing['features'].append(feature[:100])

        # Extract platform
        if 'iOS' in content:
            briefing['platform'] = 'iOS'
        elif 'macOS' in content:
            briefing['platform'] = 'macOS'

        # Extract bundle ID
        bundle_match = re.search(r'Bundle ID[:\s]*`?([a-zA-Z0-9.-]+)`?', content)
        if bundle_match:
            briefing['bundle_id'] = bundle_match.group(1)

    return briefing

@app.route('/api/xcode/projects')
def list_xcode_projects():
    """
    Lista todos os projetos Xcode (iOS e macOS)
    """
    try:
        projects = {'ios': [], 'macos': []}

        # iOS Apps
        ios_path = os.path.join(HOME, 'Apps/iOS')
        if os.path.exists(ios_path):
            for name in sorted(os.listdir(ios_path)):
                full_path = os.path.join(ios_path, name)
                if os.path.isdir(full_path):
                    projects['ios'].append({
                        'name': name,
                        'path': full_path
                    })

        # macOS Apps
        macos_path = os.path.join(HOME, 'Apps/macOS')
        if os.path.exists(macos_path):
            for name in sorted(os.listdir(macos_path)):
                full_path = os.path.join(macos_path, name)
                if os.path.isdir(full_path):
                    projects['macos'].append({
                        'name': name,
                        'path': full_path
                    })

        return jsonify({
            'status': 'ok',
            'timestamp': datetime.now().isoformat(),
            'data': projects,
            'counts': {
                'ios': len(projects['ios']),
                'macos': len(projects['macos']),
                'total': len(projects['ios']) + len(projects['macos'])
            }
        })
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/api/xcode/briefing')
def get_project_briefing_endpoint():
    """
    Get detailed briefing for a specific project
    Reads CLAUDE.md or README.md to extract summary and features
    """
    try:
        project_path = request.args.get('path', '')

        if not project_path:
            return jsonify({'status': 'error', 'message': 'Path is required'}), 400

        # Validate path is under allowed directories
        allowed_prefixes = [
            os.path.join(HOME, 'Apps/iOS'),
            os.path.join(HOME, 'Apps/macOS'),
        ]

        is_allowed = any(project_path.startswith(prefix) for prefix in allowed_prefixes)
        if not is_allowed:
            return jsonify({'status': 'error', 'message': 'Path not allowed'}), 403

        if not os.path.exists(project_path):
            return jsonify({'status': 'error', 'message': 'Project not found'}), 404

        # Get project size
        size_bytes = get_dir_size(project_path, max_depth=3)

        # Get last modified
        stat = os.stat(project_path)
        last_modified = datetime.fromtimestamp(stat.st_mtime).isoformat()

        # Get briefing from docs
        briefing = get_project_briefing(project_path)

        # Count files
        file_count = 0
        swift_count = 0
        for root, dirs, files in os.walk(project_path):
            # Skip build directories
            dirs[:] = [d for d in dirs if d not in ['build', 'DerivedData', '.git', 'Pods']]
            file_count += len(files)
            swift_count += len([f for f in files if f.endswith('.swift')])

        return jsonify({
            'status': 'ok',
            'data': {
                'name': os.path.basename(project_path),
                'path': project_path,
                'size_bytes': size_bytes,
                'size_human': format_size(size_bytes),
                'last_modified': last_modified,
                'file_count': file_count,
                'swift_files': swift_count,
                'summary': briefing['summary'],
                'features': briefing['features'],
                'bundle_id': briefing['bundle_id'],
                'has_docs': briefing['has_docs']
            }
        })
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/api/stats/summary')
def stats_summary():
    """
    Retorna resumo completo do workspace
    """
    try:
        # Contar arquivos HTML
        web_path = os.path.join(HOME, 'Web')
        web_html_count = 0
        if os.path.exists(web_path):
            find_result = subprocess.run(
                ['find', web_path, '-name', '*.html', '-type', 'f'],
                capture_output=True,
                text=True,
                timeout=30
            )
            web_html_count = len([line for line in find_result.stdout.strip().split('\n') if line])

        # Contar iOS apps
        ios_apps_path = os.path.join(HOME, 'Apps/iOS')
        ios_apps_count = 0
        if os.path.exists(ios_apps_path):
            ios_apps_count = len([
                d for d in os.listdir(ios_apps_path)
                if os.path.isdir(os.path.join(ios_apps_path, d))
            ])

        # Total de projetos
        total_projects = 0
        for category in ['core', 'tools', 'experiments']:
            path = os.path.join(HOME, 'Projects', category)
            if os.path.exists(path):
                total_projects += len([
                    d for d in os.listdir(path)
                    if os.path.isdir(os.path.join(path, d))
                ])

        # Workspace size (limited depth to avoid long scan)
        workspace_size = get_dir_size(HOME, max_depth=2)

        return jsonify({
            'status': 'ok',
            'timestamp': datetime.now().isoformat(),
            'data': {
                'web_html_files': web_html_count,
                'ios_apps': ios_apps_count,
                'projects_total': total_projects,
                'last_cleanup': get_last_cleanup_date(),
                'workspace_size_bytes': workspace_size,
                'workspace_size_human': format_size(workspace_size)
            }
        })
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

# ============================================================================
# APP LOGS (XcodeHub-iOS)
# ============================================================================

# In-memory log storage (for demo - in production use a database)
app_logs = []
MAX_LOGS = 10000

@app.route('/api/logs/batch', methods=['POST'])
def receive_logs():
    """Receive log batch from iOS app"""
    global app_logs
    try:
        data = request.get_json()
        if not data:
            return jsonify({'status': 'error', 'message': 'No data provided'}), 400

        device_id = data.get('device_id', 'unknown')
        app_version = data.get('app_version', '1.0.0')
        os_version = data.get('os_version', 'unknown')
        events = data.get('events', [])

        # Add metadata to each event
        for event in events:
            event['device_id'] = device_id
            event['app_version'] = app_version
            event['os_version'] = os_version
            event['received_at'] = datetime.now().isoformat()

        # Store logs
        app_logs.extend(events)

        # Trim old logs
        if len(app_logs) > MAX_LOGS:
            app_logs = app_logs[-MAX_LOGS:]

        # Log to console for debugging
        print(f"[LOGS] Received {len(events)} events from {device_id} (v{app_version})")

        return jsonify({
            'status': 'ok',
            'received': len(events),
            'total_stored': len(app_logs)
        })
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/api/logs')
def get_logs():
    """Get stored logs with optional filtering"""
    try:
        category = request.args.get('category')
        limit = int(request.args.get('limit', 100))

        logs = app_logs

        if category:
            logs = [l for l in logs if l.get('category') == category]

        return jsonify({
            'status': 'ok',
            'count': len(logs[-limit:]),
            'logs': logs[-limit:]
        })
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

@app.route('/api/logs/clear', methods=['POST'])
def clear_logs():
    """Clear all stored logs"""
    global app_logs
    app_logs = []
    return jsonify({'status': 'ok', 'message': 'Logs cleared'})

# ============================================================================
# PROJECT DELETION ENDPOINT
# ============================================================================

@app.route('/api/xcode/delete', methods=['POST'])
def delete_xcode_project():
    """
    Delete an Xcode project completely from the system
    Requires confirmation_code to match project name (2FA-like security)
    Aceita: {'path': '/Users/neog/Apps/iOS/AppName', 'confirmation_code': 'AppName'}
    """
    try:
        data = request.json or {}
        project_path = data.get('path', '')
        confirmation_code = data.get('confirmation_code', '')

        if not project_path:
            return jsonify({'status': 'error', 'message': 'Path is required'}), 400

        if not confirmation_code:
            return jsonify({'status': 'error', 'message': 'Confirmation code is required'}), 400

        # Validate path is under allowed directories
        allowed_prefixes = [
            os.path.join(HOME, 'Apps/iOS'),
            os.path.join(HOME, 'Apps/macOS'),
        ]

        is_allowed = any(project_path.startswith(prefix) for prefix in allowed_prefixes)
        if not is_allowed:
            return jsonify({'status': 'error', 'message': 'Path not allowed for deletion'}), 403

        if not os.path.exists(project_path):
            return jsonify({'status': 'error', 'message': 'Project not found'}), 404

        # Get project name from path
        project_name = os.path.basename(project_path)

        # 2FA: confirmation_code must match the project name exactly
        if confirmation_code != project_name:
            return jsonify({
                'status': 'error',
                'message': f'Confirmation code does not match. Expected: {project_name}'
            }), 403

        # Calculate size before deletion
        size_before = get_dir_size(project_path)

        # Delete the project
        import shutil
        shutil.rmtree(project_path)

        # Log the deletion
        print(f"[DELETE] Project deleted: {project_path} ({format_size(size_before)})")

        return jsonify({
            'status': 'ok',
            'message': f'Project {project_name} deleted successfully',
            'deleted_path': project_path,
            'freed_bytes': size_before,
            'freed_human': format_size(size_before),
            'timestamp': datetime.now().isoformat()
        })

    except PermissionError:
        return jsonify({'status': 'error', 'message': 'Permission denied'}), 403
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

# ============================================================================
# MAIN
# ============================================================================

if __name__ == '__main__':
    print("=" * 60)
    print("  Workspace Manager API Server")
    print("=" * 60)
    print(f"  Port: 9004")
    print(f"  Local: http://localhost:9004")
    print(f"  Tailscale: http://100.75.88.8:9004")
    print("=" * 60)
    print("")

    app.run(host='0.0.0.0', port=9004, debug=False)
