# -*- coding: utf-8 -*-
"""
Network Traffic Monitor - Logs all outgoing HTTP requests from Odoo.
This module patches the 'requests' library to log every HTTP call.
"""

import logging
import functools
import threading
from datetime import datetime

_logger = logging.getLogger(__name__)
_network_logger = logging.getLogger('odoo.network_traffic')

# Store for recent requests (in-memory buffer)
_request_log = []
_MAX_LOG_SIZE = 1000
_log_lock = threading.Lock()

# Flag to prevent recursive logging
_is_logging = threading.local()


def _is_odoo_call(url):
    """Check if URL is an Odoo external call."""
    odoo_domains = [
        'odoo.com', 'odoo.sh', 'iap.odoo', 'api.odoo',
        'services.odoo', 'apps.odoo', 'accounts.odoo',
        'upgrade.odoo', 'partner-autocomplete.odoo',
    ]
    url_lower = str(url).lower()
    return any(domain in url_lower for domain in odoo_domains)


def _save_to_database(log_entry):
    """Save log entry to database (async-safe)."""
    try:
        if getattr(_is_logging, 'value', False):
            return
        
        _is_logging.value = True
        
        try:
            from odoo import api, SUPERUSER_ID
            from odoo.modules.registry import Registry
            
            db_name = getattr(threading.current_thread(), 'dbname', None)
            if not db_name:
                from odoo.tools import config
                db_name = config.get('db_name')
            
            if db_name:
                registry = Registry(db_name)
                with registry.cursor() as cr:
                    env = api.Environment(cr, SUPERUSER_ID, {})
                    if 'network.log' in env:
                        env['network.log'].log_request(
                            method=log_entry.get('method', 'GET'),
                            url=log_entry.get('url', ''),
                            is_odoo_call=log_entry.get('is_odoo_call', False),
                            status_code=log_entry.get('status_code'),
                            response_time=log_entry.get('response_time_seconds'),
                            error_message=log_entry.get('error'),
                        )
                        cr.commit()
        except Exception as e:
            _logger.debug("Could not save network log to database: %s", e)
    finally:
        _is_logging.value = False


def _log_request(method, url, **kwargs):
    """Log details of an HTTP request."""
    timestamp = datetime.now().isoformat()
    
    log_entry = {
        'timestamp': timestamp,
        'method': method.upper(),
        'url': str(url),
        'timeout': kwargs.get('timeout'),
        'is_odoo_call': _is_odoo_call(url),
    }
    
    if log_entry['is_odoo_call']:
        _network_logger.warning("ODOO EXTERNAL CALL: %s %s", method.upper(), url)
    else:
        _network_logger.info("HTTP Request: %s %s", method.upper(), url)
    
    with _log_lock:
        _request_log.append(log_entry)
        if len(_request_log) > _MAX_LOG_SIZE:
            _request_log.pop(0)
    
    return log_entry


def _log_response(log_entry, response=None, error=None):
    """Log the response of an HTTP request."""
    if response is not None:
        log_entry['status_code'] = response.status_code
        if hasattr(response, 'elapsed') and hasattr(response.elapsed, 'total_seconds'):
            log_entry['response_time_seconds'] = response.elapsed.total_seconds()
        
        _network_logger.info("Response: %s %s -> %d",
            log_entry['method'], log_entry['url'], response.status_code)
    elif error is not None:
        log_entry['error'] = str(error)
        _network_logger.error("Error: %s %s -> %s",
            log_entry['method'], log_entry['url'], error)
    
    _save_to_database(log_entry)


def _wrap_request_method(original_method, method_name):
    """Wrap a requests method to add logging."""
    @functools.wraps(original_method)
    def wrapper(url, *args, **kwargs):
        if 'localhost:65535' in str(url):
            return original_method(url, *args, **kwargs)
        
        log_entry = _log_request(method_name, url, **kwargs)
        try:
            response = original_method(url, *args, **kwargs)
            _log_response(log_entry, response=response)
            return response
        except Exception as e:
            _log_response(log_entry, error=e)
            raise
    return wrapper


def patch_requests_library():
    """Monkey-patch the requests library to log all HTTP calls."""
    try:
        import requests
        
        if not hasattr(requests, '_original_get'):
            requests._original_get = requests.get
            requests._original_post = requests.post
            requests._original_put = requests.put
            requests._original_delete = requests.delete
            requests._original_patch = requests.patch
            requests._original_head = requests.head
            requests._original_options = requests.options
        
        requests.get = _wrap_request_method(requests._original_get, 'GET')
        requests.post = _wrap_request_method(requests._original_post, 'POST')
        requests.put = _wrap_request_method(requests._original_put, 'PUT')
        requests.delete = _wrap_request_method(requests._original_delete, 'DELETE')
        requests.patch = _wrap_request_method(requests._original_patch, 'PATCH')
        requests.head = _wrap_request_method(requests._original_head, 'HEAD')
        requests.options = _wrap_request_method(requests._original_options, 'OPTIONS')
        
        _logger.info("NETWORK LOGGER: All HTTP requests are now being monitored")
        
    except ImportError:
        _logger.warning("Could not import requests library for patching")
    except Exception as e:
        _logger.error("Error patching requests library: %s", e)


# Apply patch when module is loaded
patch_requests_library()

