"""
HTTP server for RateLoader functionality.

Implements HTTP endpoints for receiving price data and managing the RateLoader service.
Handles JSON parsing, error responses, and submits work to thread pool as per legacy behavior.
"""

import json
import threading
import time
from http.server import HTTPServer, BaseHTTPRequestHandler
from concurrent.futures import ThreadPoolExecutor
from typing import Dict, Any, Optional
from urllib.parse import urlparse, parse_qs

from core.config import get_config
from core.logger import get_rateloader_logger, get_http_logger
from core.oracle import create_oracle_wrapper
from core.task_queue import get_queue_status
from core.scheduler import get_scheduler_status
from features.rate_loader_logic import process_prices, parse_json_data


class RateLoaderRequestHandler(BaseHTTPRequestHandler):
    """HTTP request handler for RateLoader endpoints."""
    
    def __init__(self, *args, oracle_connector=None, executor=None, ip_manager=None, **kwargs):
        """
        Initialize request handler.
        
        Args:
            oracle_connector: Oracle database connection
            executor: Thread pool executor for background tasks
            ip_manager: IP address manager for access control
        """
        self.oracle_connector = oracle_connector
        self.executor = executor
        self.ip_manager = ip_manager
        self.logger = get_http_logger()
        super().__init__(*args, **kwargs)
    
    def do_GET(self):
        """Handle GET requests."""
        try:
            # Check IP access before processing
            if not self._check_ip_access():
                return
            
            parsed_path = urlparse(self.path)
            
            if parsed_path.path == "/":
                self._handle_ping()
            elif parsed_path.path == "/ping":
                self._handle_ping()
            elif parsed_path.path == "/status":
                self._handle_status()
            else:
                self._send_404()
                
        except Exception as e:
            self.logger.error(f"Error handling GET request to {self.path}: {str(e)}")
            self._send_500()
    
    def do_POST(self):
        """Handle POST requests."""
        try:
            # Check IP access before processing
            if not self._check_ip_access():
                return
            
            parsed_path = urlparse(self.path)
            
            if parsed_path.path == "/load":
                self._handle_load()
            else:
                self._send_404()
                
        except Exception as e:
            self.logger.error(f"Error handling POST request to {self.path}: {str(e)}")
            self._send_500()
    
    def _handle_ping(self):
        """Handle /ping endpoint - returns simple status."""
        self.logger.debug("Received ping request")
        response = {"status": "ok"}
        self._send_json_response(200, response)
    
    def _handle_status(self):
        """Handle /status endpoint - returns queue status summary."""
        self.logger.debug("Received status request")
        
        # Get task queue status
        queue_status = get_queue_status()
        
        # Get scheduler status
        scheduler_status = get_scheduler_status()
        
        # Build comprehensive status
        status = {
            "server": "running",
            "timestamp": time.time(),
            "task_queue": queue_status,
            "scheduler": scheduler_status,
            "oracle_connected": self.oracle_connector is not None and self.oracle_connector.is_connected()
        }
        
        self._send_json_response(200, status)
    
    def _handle_load(self):
        """Handle /load endpoint - accepts JSON price data and processes it."""
        self.logger.info("Received load request")
        
        try:
            # Read request body
            content_length = int(self.headers.get('Content-Length', 0))
            if content_length == 0:
                self._send_error_response(400, "Empty request body")
                return
                
            post_data = self.rfile.read(content_length).decode('utf-8')
            
            # Parse JSON
            data = parse_json_data(post_data)
            if data is None:
                self._send_error_response(400, "Invalid JSON format")
                return
            
            # Submit work to thread pool (legacy behavior)
            if self.executor:
                self.logger.info("Submitting price processing to thread pool")
                self.executor.submit(process_prices, data, self.oracle_connector)
            else:
                # Fallback to direct processing if no executor
                self.logger.warning("No thread pool available, processing directly")
                process_prices(data, self.oracle_connector)
            
            # Respond immediately with legacy response format
            self._send_text_response(200, f"POST request for {self.path}")
            self.logger.info(f"Load request processed and queued for {self.path}")
            
        except Exception as e:
            self.logger.error(f"Error processing load request: {str(e)}")
            self._send_500()
    
    def _send_json_response(self, status_code: int, data: Dict[str, Any]):
        """Send JSON response."""
        response_data = json.dumps(data).encode('utf-8')
        
        self.send_response(status_code)
        self.send_header('Content-Type', 'application/json')
        self.send_header('Content-Length', str(len(response_data)))
        self.end_headers()
        self.wfile.write(response_data)
    
    def _send_text_response(self, status_code: int, text: str):
        """Send plain text response."""
        response_data = text.encode('utf-8')
        
        self.send_response(status_code)
        self.send_header('Content-Type', 'text/plain')
        self.send_header('Content-Length', str(len(response_data)))
        self.end_headers()
        self.wfile.write(response_data)
    
    def _send_error_response(self, status_code: int, message: str):
        """Send error response."""
        self.logger.warning(f"Sending error response {status_code}: {message}")
        error_data = {"error": message}
        self._send_json_response(status_code, error_data)
    
    def _send_404(self):
        """Send 404 Not Found response."""
        self._send_error_response(404, "Not Found")
    
    def _send_500(self):
        """Send 500 Internal Server Error response."""
        self._send_error_response(500, "Internal Server Error")
    
    def _send_403(self):
        """Send 403 Forbidden response."""
        self.logger.warning(f"Access denied for IP {self.client_address[0]}")
        error_data = {"error": "Access denied", "message": "Your IP address is not allowed to access this service"}
        self._send_json_response(403, error_data)
    
    def _check_ip_access(self) -> bool:
        """
        Check if client IP is allowed to access the server.
        
        Returns:
            True if access is allowed, False otherwise
        """
        try:
            client_ip = self.client_address[0]
            
            # If no IP manager is available, allow access (fail open)
            if self.ip_manager is None:
                self.logger.debug(f"No IP manager available, allowing access from {client_ip}")
                return True
            
            # Check IP access first
            if not self.ip_manager.is_ip_allowed(client_ip):
                # Access denied
                self._send_403()
                return False

            # Access allowed - record request
            self.ip_manager.record_request(client_ip, "GET" if self.command == "GET" else "POST")
            return True
                
        except Exception as e:
            self.logger.error(f"Error checking IP access: {str(e)}")
            # Fail open - allow access if there's an error
            return True
    
    def log_message(self, format, *args):
        """Override default logging to use our logger."""
        self.logger.debug(f"{self.address_string()} - {format % args}")


class RateLoaderHTTPServer:
    """HTTP server for RateLoader with start/stop functionality."""
    
    def __init__(self, port: Optional[int] = None, max_workers: int = 5):
        """
        Initialize HTTP server.
        
        Args:
            port: Server port. If None, uses server_port from settings.ini
            max_workers: Maximum number of worker threads
        """
        self.config = get_config()
        self.logger = get_http_logger()
        
        # Get server port from config or use provided value
        self.port = port if port is not None else self.config.get_int("server_port", fallback=8000)
        
        # Initialize Oracle connector
        self.oracle_connector = create_oracle_wrapper()
        
        # Initialize thread pool executor
        self.executor = ThreadPoolExecutor(max_workers=max_workers)
        
        # IP manager (will be set later)
        self.ip_manager = None
        
        # Server instance
        self.server = None
        self.server_thread = None
        self.is_running = False
    
    def start(self) -> bool:
        """
        Start the HTTP server in a separate thread.
        
        Returns:
            True if server started successfully, False otherwise
        """
        if self.is_running:
            self.logger.warning("Server is already running")
            return True
        
        try:
            # Create handler with dependencies
            def handler_factory(*args, **kwargs):
                return RateLoaderRequestHandler(
                    *args,
                    oracle_connector=self.oracle_connector,
                    executor=self.executor,
                    ip_manager=self.ip_manager,
                    **kwargs
                )
            
            # Create and start server
            self.server = HTTPServer(('0.0.0.0', self.port), handler_factory)
            self.server_thread = threading.Thread(target=self._run_server, daemon=True)
            self.server_thread.start()
            
            self.is_running = True
            self.logger.info(f"RateLoader HTTP server started on port {self.port}")
            return True
            
        except Exception as e:
            self.logger.error(f"Failed to start HTTP server: {str(e)}")
            return False
    
    def stop(self) -> bool:
        """
        Stop the HTTP server.
        
        Returns:
            True if server stopped successfully, False otherwise
        """
        if not self.is_running:
            self.logger.warning("Server is not running")
            return True
        
        try:
            if self.server:
                self.server.shutdown()
                self.server.server_close()
                self.logger.info("HTTP server stopped")
            
            if self.server_thread and self.server_thread.is_alive():
                self.server_thread.join(timeout=5)
            
            self.is_running = False
            return True
            
        except Exception as e:
            self.logger.error(f"Error stopping HTTP server: {str(e)}")
            return False
    
    def _run_server(self):
        """Run the server in the thread."""
        try:
            self.logger.info(f"Server listening on port {self.port}")
            self.server.serve_forever()
        except Exception as e:
            self.logger.error(f"Server error: {str(e)}")
    
    def cleanup(self):
        """Clean up resources."""
        try:
            # Stop server if running
            if self.is_running:
                self.stop()
            
            # Shutdown executor
            if self.executor:
                self.executor.shutdown(wait=True)
            
            # Close Oracle connection
            if self.oracle_connector:
                self.oracle_connector.disconnect()
                
            self.logger.info("HTTP server cleanup completed")
            
        except Exception as e:
            self.logger.error(f"Error during cleanup: {str(e)}")
    
    def set_ip_manager(self, ip_manager):
        """
        Set IP manager instance.
        
        Args:
            ip_manager: IP manager instance for access control
        """
        self.ip_manager = ip_manager
        self.logger.info("IP manager set in HTTP server")


# Global server instance
_server_instance = None


def get_http_server() -> RateLoaderHTTPServer:
    """
    Get the global HTTP server instance.
    
    Returns:
        Global RateLoaderHTTPServer instance
    """
    global _server_instance
    if _server_instance is None:
        _server_instance = RateLoaderHTTPServer()
    return _server_instance


def start_server(port: Optional[int] = None) -> bool:
    """
    Start the RateLoader HTTP server.
    
    Args:
        port: Server port. If None, uses server_port from settings.ini
        
    Returns:
        True if server started successfully, False otherwise
    """
    server = get_http_server()
    if port is not None:
        server.port = port
    return server.start()


def stop_server() -> bool:
    """
    Stop the RateLoader HTTP server.
    
    Returns:
        True if server stopped successfully, False otherwise
    """
    server = get_http_server()
    return server.stop()


def is_server_running() -> bool:
    """
    Check if the HTTP server is running.
    
    Returns:
        True if server is running, False otherwise
    """
    server = get_http_server()
    return server.is_running