"""
NovaLang HTTP Server - Flask-based REST API Server
Handles routing, CORS, request/response processing
"""

from flask import Flask, request, jsonify, make_response
from flask_cors import CORS
from typing import Dict, List, Any, Callable, Optional
import json
import logging
from dataclasses import dataclass

@dataclass
class Route:
    """REST API route definition"""
    path: str
    method: str  # GET, POST, PUT, DELETE
    handler: Callable
    controller_class: str
    function_name: str

class NovaLangHTTPServer:
    """HTTP Server for NovaLang REST APIs"""
    
    def __init__(self, host: str = "0.0.0.0", port: int = 8080):
        self.app = Flask(__name__)
        self.host = host
        self.port = port
        self.routes: List[Route] = []
        self.controllers: Dict[str, Any] = {}
        self.services: Dict[str, Any] = {}
        self.repositories: Dict[str, Any] = {}
        
        # Setup logging
        logging.basicConfig(level=logging.INFO)
        self.logger = logging.getLogger(__name__)
        
        # Configure CORS - will be updated with config
        self.cors_config = {
            'origins': ['http://localhost:3000', 'http://localhost:4200', 'http://localhost:5173'],
            'methods': ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
            'allow_headers': ['Content-Type', 'Authorization'],
            'supports_credentials': True
        }
        CORS(self.app, resources={r"/api/*": self.cors_config})
        
    def configure_cors(self, origins: List[str] = None, methods: List[str] = None):
        """Configure CORS settings"""
        if origins:
            self.cors_config['origins'] = origins
        if methods:
            self.cors_config['methods'] = methods
        
        # Reconfigure CORS
        CORS(self.app, resources={r"/api/*": self.cors_config})
        self.logger.info(f"🛡️  CORS configured for origins: {', '.join(self.cors_config['origins'])}")
    
    def register_controller(self, controller_name: str, controller_instance: Any):
        """Register a controller instance"""
        self.controllers[controller_name] = controller_instance
        self.logger.info(f"🎮 Registered controller: {controller_name}")
    
    def register_service(self, service_name: str, service_instance: Any):
        """Register a service instance"""
        self.services[service_name] = service_instance
        self.logger.info(f"⚙️  Registered service: {service_name}")
    
    def register_repository(self, repo_name: str, repo_instance: Any):
        """Register a repository instance"""
        self.repositories[repo_name] = repo_instance
        self.logger.info(f"🔧 Registered repository: {repo_name}")
    
    def add_route(self, path: str, method: str, handler: Callable, 
                  controller_class: str, function_name: str):
        """Add a REST API route"""
        route = Route(
            path=path,
            method=method,
            handler=handler,
            controller_class=controller_class,
            function_name=function_name
        )
        self.routes.append(route)
        
        # Register with Flask
        endpoint_name = f"{controller_class}.{function_name}.{method}"
        
        if method == 'GET':
            self.app.route(path, methods=['GET'], endpoint=endpoint_name)(
                self._create_flask_handler(route)
            )
        elif method == 'POST':
            self.app.route(path, methods=['POST'], endpoint=endpoint_name)(
                self._create_flask_handler(route)
            )
        elif method == 'PUT':
            self.app.route(path, methods=['PUT'], endpoint=endpoint_name)(
                self._create_flask_handler(route)
            )
        elif method == 'DELETE':
            self.app.route(path, methods=['DELETE'], endpoint=endpoint_name)(
                self._create_flask_handler(route)
            )
        
        self.logger.info(f"🌐 Registered route: {method} {path} -> {controller_class}.{function_name}")
    
    def _create_flask_handler(self, route: Route):
        """Create a Flask route handler"""
        def flask_handler(**kwargs):
            try:
                # Get request body for POST/PUT
                body = None
                if request.method in ['POST', 'PUT']:
                    if request.is_json:
                        body = request.get_json()
                    else:
                        body = request.form.to_dict()
                
                # Get query parameters
                query_params = request.args.to_dict()
                
                # Merge path parameters and query parameters
                params = {**kwargs, **query_params}
                
                # Call the handler
                if body:
                    params['body'] = body
                
                result = route.handler(**params)
                
                # Handle NovaLang Response objects
                if isinstance(result, dict) and 'status' in result and 'data' in result:
                    response = make_response(jsonify(result['data']), result['status'])
                    if 'headers' in result:
                        for key, value in result['headers'].items():
                            response.headers[key] = value
                    return response
                
                # Default: return as JSON with 200
                return jsonify(result), 200
                
            except Exception as e:
                self.logger.error(f"Error in {route.controller_class}.{route.function_name}: {str(e)}")
                return jsonify({'error': str(e)}), 500
        
        return flask_handler
    
    def add_health_check(self):
        """Add health check endpoint"""
        @self.app.route('/actuator/health', methods=['GET'])
        def health_check():
            return jsonify({
                'status': 'UP',
                'application': 'NovaLang Backend',
                'version': '3.0.0'
            }), 200
        
        self.logger.info("✅ Health check endpoint: GET /actuator/health")
    
    def add_api_docs(self):
        """Add API documentation endpoint"""
        @self.app.route('/api/docs', methods=['GET'])
        def api_docs():
            routes_info = []
            for route in self.routes:
                routes_info.append({
                    'method': route.method,
                    'path': route.path,
                    'controller': route.controller_class,
                    'function': route.function_name
                })
            
            return jsonify({
                'title': 'NovaLang REST API Documentation',
                'version': '3.0.0',
                'endpoints': routes_info
            }), 200
        
        self.logger.info("📚 API docs endpoint: GET /api/docs")
    
    def start(self):
        """Start the HTTP server"""
        # Add standard endpoints
        self.add_health_check()
        self.add_api_docs()
        
        print(f"\n{'='*50}")
        print(f"  🚀 NovaLang HTTP Server Starting")
        print(f"{'='*50}")
        print(f"🌐 Server URL: http://{self.host}:{self.port}")
        print(f"📚 API Docs: http://{self.host}:{self.port}/api/docs")
        print(f"✅ Health Check: http://{self.host}:{self.port}/actuator/health")
        print(f"🛡️  CORS Enabled: {', '.join(self.cors_config['origins'])}")
        print(f"📡 Registered {len(self.routes)} endpoints")
        print(f"{'='*50}\n")
        
        # Start Flask server
        try:
            self.app.run(host=self.host, port=self.port, debug=False)
        except KeyboardInterrupt:
            print("\n\n🛑 Server stopped by user")
        except Exception as e:
            self.logger.error(f"Server error: {e}")
            raise

# Response helper class
class Response:
    """HTTP Response helper"""
    
    @staticmethod
    def ok(data: Any, headers: Dict = None):
        """200 OK response"""
        return {'status': 200, 'data': data, 'headers': headers or {}}
    
    @staticmethod
    def created(data: Any, headers: Dict = None):
        """201 Created response"""
        return {'status': 201, 'data': data, 'headers': headers or {}}
    
    @staticmethod
    def no_content(headers: Dict = None):
        """204 No Content response"""
        return {'status': 204, 'data': None, 'headers': headers or {}}
    
    @staticmethod
    def bad_request(message: str, headers: Dict = None):
        """400 Bad Request response"""
        return {'status': 400, 'data': {'error': message}, 'headers': headers or {}}
    
    @staticmethod
    def not_found(message: str, headers: Dict = None):
        """404 Not Found response"""
        return {'status': 404, 'data': {'error': message}, 'headers': headers or {}}
    
    @staticmethod
    def internal_error(message: str, headers: Dict = None):
        """500 Internal Server Error response"""
        return {'status': 500, 'data': {'error': message}, 'headers': headers or {}}
