#!/usr/bin/env nu

# API Server for Provisioning System
# Provides HTTP REST API endpoints for infrastructure queries and management

use ../lib_provisioning/utils/settings.nu *
use ../main_provisioning/query.nu *
use ../lib_provisioning/ai/lib.nu *

export def start_api_server [
    --port: int = 8080
    --host: string = "localhost"
    --enable-websocket
    --enable-cors
    --debug
]: nothing -> nothing {
    print $"🚀 Starting Provisioning API Server on ($host):($port)"

    if $debug {
        $env.PROVISIONING_API_DEBUG = "true"
        print "Debug mode enabled"
    }

    # Check if port is available
    let port_check = (check_port_available $port)
    if not $port_check {
        error make {
            msg: $"Port ($port) is already in use"
            help: "Try a different port with --port flag"
        }
    }

    # Setup server configuration
    let server_config = {
        host: $host
        port: $port
        enable_websocket: $enable_websocket
        enable_cors: $enable_cors
        debug: $debug
        routes: (get_api_routes)
    }

    print $"📡 Server configuration: ($server_config | to json)"
    print "Available endpoints:"
    print "  GET  /api/v1/health         - Health check"
    print "  GET  /api/v1/query          - Infrastructure queries"
    print "  POST /api/v1/query          - Complex queries with body"
    print "  GET  /api/v1/metrics        - System metrics"
    print "  GET  /api/v1/logs           - System logs"
    print "  GET  /api/v1/dashboard      - Dashboard data"
    if $enable_websocket {
        print "  WS   /ws/stream            - WebSocket real-time updates"
    }

    # Start HTTP server
    start_http_server $server_config
}

def check_port_available [port: int]: nothing -> bool {
    # Try to bind to the port to check if it's available
    let result = (do -i {
        http listen $port --host "127.0.0.1" --timeout 1 | ignore
    })

    match $result {
        null => false,   # Port is busy
        _ => true        # Port is available
    }
}

def get_api_routes []: nothing -> list {
    [
        { method: "GET", path: "/api/v1/health", handler: "handle_health" }
        { method: "GET", path: "/api/v1/query", handler: "handle_query_get" }
        { method: "POST", path: "/api/v1/query", handler: "handle_query_post" }
        { method: "GET", path: "/api/v1/metrics", handler: "handle_metrics" }
        { method: "GET", path: "/api/v1/logs", handler: "handle_logs" }
        { method: "GET", path: "/api/v1/dashboard", handler: "handle_dashboard" }
        { method: "GET", path: "/api/v1/servers", handler: "handle_servers" }
        { method: "GET", path: "/api/v1/servers/{id}/status", handler: "handle_server_status" }
    ]
}

def start_http_server [config: record]: nothing -> nothing {
    print $"🌐 Starting HTTP server on ($config.host):($config.port)..."

    # Use a Python-based HTTP server for better compatibility
    let server_script = create_python_server $config

    # Save server script to temporary file
    let temp_server = $"/tmp/provisioning_api_server.py"
    $server_script | save --force $temp_server

    print $"📝 Server script saved to: ($temp_server)"
    print "🎯 Starting server... (Press Ctrl+C to stop)"

    # Start the Python server
    python3 $temp_server
}

def create_python_server [config: record]: nothing -> str {
    let cors_headers = if $config.enable_cors {
        '''
        self.send_header('Access-Control-Allow-Origin', '*')
        self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
        self.send_header('Access-Control-Allow-Headers', 'Content-Type')
        '''
    } else { "" }

    let websocket_import = if $config.enable_websocket {
        "import websockets"
    } else { "" }

    $"#!/usr/bin/env python3
import http.server
import socketserver
import json
import subprocess
import urllib.parse
import os
from pathlib import Path
($websocket_import)

class ProvisioningAPIHandler(http.server.BaseHTTPRequestHandler):
    def do_OPTIONS(self):
        self.send_response(200)
        ($cors_headers)
        self.end_headers()

    def do_GET(self):
        self.handle_request('GET')

    def do_POST(self):
        self.handle_request('POST')

    def handle_request(self, method):
        try:
            path_parts = urllib.parse.urlparse(self.path)
            path = path_parts.path
            query_params = urllib.parse.parse_qs(path_parts.query)

            # Route handling
            if path == '/api/v1/health':
                self.handle_health()
            elif path == '/api/v1/query':
                if method == 'GET':
                    self.handle_query_get(query_params)
                else:
                    self.handle_query_post()
            elif path == '/api/v1/metrics':
                self.handle_metrics(query_params)
            elif path == '/api/v1/logs':
                self.handle_logs(query_params)
            elif path == '/api/v1/dashboard':
                self.handle_dashboard(query_params)
            elif path == '/api/v1/servers':
                self.handle_servers(query_params)
            elif path.startswith('/api/v1/servers/') and path.endswith('/status'):
                server_id = path.split('/')[-2]
                self.handle_server_status(server_id, query_params)
            else:
                self.send_error(404, 'Not Found')
        except Exception as e:
            self.send_error(500, f'Internal Server Error: {{str(e)}}')

    def handle_health(self):
        response = {{
            'status': 'healthy',
            'service': 'provisioning-api',
            'version': '1.0.0',
            'timestamp': self.get_timestamp()
        }}
        self.send_json_response(response)

    def handle_query_get(self, params):
        # Convert query parameters to nushell command
        target = params.get('target', ['servers'])[0]
        infra = params.get('infra', [None])[0]
        find = params.get('find', [None])[0]
        cols = params.get('cols', [None])[0]
        out_format = params.get('format', ['json'])[0]

        cmd_args = ['nu', '-c', f'use ($env.PROVISIONING_PATH)/core/nulib/main_provisioning/query.nu; main query {{target}} --out {{out_format}}']
        if infra:
            cmd_args[-1] = cmd_args[-1].replace('{{target}}', f'{{target}} --infra {{infra}}')

        result = self.run_provisioning_command(cmd_args)
        self.send_json_response(result)

    def handle_query_post(self):
        content_length = int(self.headers.get('Content-Length', 0))
        if content_length > 0:
            post_data = self.rfile.read(content_length)
            try:
                query_data = json.loads(post_data.decode('utf-8'))
                # Process complex query
                result = self.process_complex_query(query_data)
                self.send_json_response(result)
            except json.JSONDecodeError:
                self.send_error(400, 'Invalid JSON')
        else:
            self.send_error(400, 'No data provided')

    def handle_metrics(self, params):
        timerange = params.get('timerange', ['1h'])[0]
        metric_type = params.get('type', ['all'])[0]

        # Mock metrics data - replace with actual metrics collection
        metrics = {{
            'cpu_usage': {{
                'current': 45.2,
                'average': 38.7,
                'max': 89.1,
                'unit': 'percentage'
            }},
            'memory_usage': {{
                'current': 2.3,
                'total': 8.0,
                'unit': 'GB'
            }},
            'disk_usage': {{
                'used': 120.5,
                'total': 500.0,
                'unit': 'GB'
            }},
            'network_io': {{
                'in': 1024,
                'out': 2048,
                'unit': 'MB/s'
            }},
            'timestamp': self.get_timestamp(),
            'timerange': timerange
        }}

        self.send_json_response(metrics)

    def handle_logs(self, params):
        level = params.get('level', ['info'])[0]
        limit = int(params.get('limit', ['100'])[0])
        since = params.get('since', ['1h'])[0]

        # Mock log data - replace with actual log collection
        logs = {{
            'entries': [
                {{
                    'timestamp': '2024-01-16T10:30:00Z',
                    'level': 'info',
                    'service': 'provisioning-core',
                    'message': 'Server created successfully: web-01'
                }},
                {{
                    'timestamp': '2024-01-16T10:29:45Z',
                    'level': 'debug',
                    'service': 'aws-provider',
                    'message': 'EC2 instance launched: i-1234567890abcdef0'
                }}
            ],
            'total': 2,
            'filters': {{
                'level': level,
                'limit': limit,
                'since': since
            }}
        }}

        self.send_json_response(logs)

    def handle_dashboard(self, params):
        view = params.get('view', ['overview'])[0]

        dashboard_data = {{
            'overview': {{
                'total_servers': 25,
                'active_servers': 23,
                'failed_servers': 2,
                'total_cost_monthly': 3250.75,
                'cost_trend': '+5.2%',
                'uptime': 99.7
            }},
            'recent_activities': [
                {{
                    'type': 'deployment',
                    'message': 'Deployed application to production',
                    'timestamp': '2024-01-16T10:30:00Z',
                    'status': 'success'
                }},
                {{
                    'type': 'scaling',
                    'message': 'Auto-scaled web servers: 3 → 5',
                    'timestamp': '2024-01-16T10:25:00Z',
                    'status': 'success'
                }}
            ],
            'alerts': [
                {{
                    'severity': 'warning',
                    'message': 'High CPU usage on web-01',
                    'timestamp': '2024-01-16T10:28:00Z'
                }}
            ]
        }}

        self.send_json_response(dashboard_data)

    def handle_servers(self, params):
        status_filter = params.get('status', [None])[0]
        provider = params.get('provider', [None])[0]

        # Use actual provisioning query command
        cmd_args = ['nu', '-c', f'use ($env.PROVISIONING_PATH)/core/nulib/main_provisioning/query.nu; main query servers --out json']
        result = self.run_provisioning_command(cmd_args)
        self.send_json_response(result)

    def handle_server_status(self, server_id, params):
        # Mock server status - replace with actual server status check
        server_status = {{
            'server_id': server_id,
            'status': 'running',
            'uptime': '5d 12h 30m',
            'cpu_usage': 34.2,
            'memory_usage': 68.5,
            'disk_usage': 45.1,
            'network_in': 125.6,
            'network_out': 89.3,
            'last_check': self.get_timestamp()
        }}

        self.send_json_response(server_status)

    def run_provisioning_command(self, cmd_args):
        try:
            result = subprocess.run(
                cmd_args,
                capture_output=True,
                text=True,
                env={{**os.environ, 'PROVISIONING_OUT': 'json'}}
            )

            if result.returncode == 0:
                try:
                    return json.loads(result.stdout)
                except json.JSONDecodeError:
                    return {{'output': result.stdout, 'raw': True}}
            else:
                return {{'error': result.stderr, 'returncode': result.returncode}}

        except Exception as e:
            return {{'error': str(e), 'type': 'execution_error'}}

    def process_complex_query(self, query_data):
        # Process complex queries with AI if available
        if 'ai_query' in query_data:
            # Use AI processing
            ai_result = self.process_ai_query(query_data['ai_query'])
            return ai_result
        else:
            # Standard complex query processing
            return {{'result': 'Complex query processed', 'data': query_data}}

    def process_ai_query(self, ai_query):
        try:
            cmd_args = [
                'nu', '-c',
                f'use ($env.PROVISIONING_PATH)/core/nulib/main_provisioning/query.nu; main query --ai-query \"{{ai_query}}\" --out json'
            ]
            result = self.run_provisioning_command(cmd_args)
            return result
        except Exception as e:
            return {{'error': f'AI query failed: {{str(e)}}'}}

    def send_json_response(self, data):
        self.send_response(200)
        self.send_header('Content-Type', 'application/json')
        ($cors_headers)
        self.end_headers()

        json_data = json.dumps(data, indent=2, ensure_ascii=False)
        self.wfile.write(json_data.encode('utf-8'))

    def get_timestamp(self):
        from datetime import datetime
        return datetime.utcnow().isoformat() + 'Z'

    def log_message(self, format, *args):
        if os.getenv('PROVISIONING_API_DEBUG') == 'true':
            super().log_message(format, *args)

if __name__ == '__main__':
    HOST = '($config.host)'
    PORT = ($config.port)

    # Set environment variables
    os.environ['PROVISIONING_PATH'] = '($env.PROVISIONING_PATH | default "/usr/local/provisioning")'

    with socketserver.TCPServer((HOST, PORT), ProvisioningAPIHandler) as httpd:
        print(f'🌐 Provisioning API Server running on http://{{HOST}}:{{PORT}}')
        print('📋 Available endpoints:')
        print('  GET  /api/v1/health')
        print('  GET  /api/v1/query')
        print('  POST /api/v1/query')
        print('  GET  /api/v1/metrics')
        print('  GET  /api/v1/logs')
        print('  GET  /api/v1/dashboard')
        print('  GET  /api/v1/servers')
        print('  GET  /api/v1/servers/{{id}}/status')
        print('\\n🎯 Server ready! Press Ctrl+C to stop')

        try:
            httpd.serve_forever()
        except KeyboardInterrupt:
            print('\\n🛑 Server shutting down...')
            httpd.shutdown()
            print('✅ Server stopped')
"
}

# WebSocket server for real-time updates (if enabled)
export def start_websocket_server [
    --port: int = 8081
    --host: string = "localhost"
]: nothing -> nothing {
    print $"🔗 Starting WebSocket server on ($host):($port) for real-time updates"
    print "This feature requires additional WebSocket implementation"
    print "Consider using a Rust-based WebSocket server for production use"
}

# Health check for the API server
export def check_api_health [
    --host: string = "localhost"
    --port: int = 8080
]: nothing -> record {
    try {
        let response = http get $"http://($host):($port)/api/v1/health"
        {
            status: "healthy",
            api_server: true,
            response: $response
        }
    } catch {
        {
            status: "unhealthy",
            api_server: false,
            error: "Cannot connect to API server"
        }
    }
}