# -*- coding: utf-8 -*-
# Copyright 2026 Nexa Systems Inc.
# License OPL-1 (Odoo Proprietary License v1.0)

import json
import logging
import time
from collections import defaultdict

from odoo import http
from odoo.http import request, Response

from ..lib.woo_api_client import WooApiClient

_logger = logging.getLogger(__name__)


def _normalize_url(url):
    """Strip trailing slashes and lowercase for comparison."""
    return url.rstrip('/').lower() if url else ''


class WooWebhookController(http.Controller):
    """Receive inbound WooCommerce webhook deliveries."""

    # Simple in-memory rate limiter: {ip: [(timestamp, ...),]}
    _rate_tracker = defaultdict(list)
    _RATE_LIMIT = 100  # max requests per minute
    _RATE_WINDOW = 60  # seconds

    @classmethod
    def _check_rate_limit(cls, ip):
        """Return True if the IP is within rate limits, False if exceeded."""
        now = time.time()
        cutoff = now - cls._RATE_WINDOW
        # Clean old entries
        cls._rate_tracker[ip] = [
            ts for ts in cls._rate_tracker[ip] if ts > cutoff
        ]
        if len(cls._rate_tracker[ip]) >= cls._RATE_LIMIT:
            return False
        cls._rate_tracker[ip].append(now)
        return True

    def _find_instance(self, source_url):
        """Find a woo.instance matching the webhook source URL."""
        instances = request.env['woo.instance'].sudo().search([
            ('state', '!=', 'draft'),
        ])
        norm_source = _normalize_url(source_url)
        for inst in instances:
            if _normalize_url(inst.url) == norm_source:
                return inst
        return None

    def _handle_ping(self, topic):
        """Return 200 for WooCommerce webhook test deliveries."""
        _logger.info("WooCommerce webhook ping received. Topic: %s", topic)
        return Response('OK', status=200)

    def _verify_and_dispatch(self, dispatch_method):
        """
        Common handler for all webhook endpoints.
        - Rate limits by IP
        - Detects ping
        - Finds instance by source URL
        - Verifies HMAC signature
        - Delegates to dispatch_method(instance, data)
        Returns a Response.
        """
        # Rate limiting
        remote_ip = request.httprequest.remote_addr or 'unknown'
        if not self._check_rate_limit(remote_ip):
            _logger.warning("Rate limit exceeded for IP %s", remote_ip)
            return Response('Too Many Requests', status=429)

        headers = request.httprequest.headers
        topic = headers.get('X-WC-Webhook-Topic', '')
        source_url = headers.get('X-WC-Webhook-Source', '')
        signature = headers.get('X-WC-Webhook-Signature', '')

        payload = request.httprequest.get_data()

        # WooCommerce sends a test ping on webhook creation — body may be empty or minimal
        if not payload or payload.strip() in (b'', b'{}', b'[]'):
            return self._handle_ping(topic)

        # Find matching instance
        instance = self._find_instance(source_url)
        if not instance:
            _logger.warning(
                "WooCommerce webhook: no matching instance for source URL '%s'", source_url
            )
            # Return 200 to prevent WooCommerce from retrying indefinitely
            return Response('No matching instance', status=200)

        # Verify HMAC signature
        if instance.webhook_secret:
            if not WooApiClient.verify_webhook_signature(payload, signature, instance.webhook_secret):
                _logger.warning(
                    "WooCommerce webhook: invalid signature for instance '%s'", instance.name
                )
                return Response('Unauthorized', status=401)
        else:
            _logger.warning(
                "WooCommerce webhook: instance '%s' has no webhook_secret — skipping signature check",
                instance.name,
            )

        # Parse JSON body
        try:
            data = json.loads(payload)
        except (json.JSONDecodeError, ValueError) as exc:
            _logger.error("WooCommerce webhook: invalid JSON body — %s", exc)
            return Response('Bad Request', status=400)

        # Dispatch to model method
        try:
            dispatch_method(instance, data, topic)
        except Exception:
            _logger.exception(
                "WooCommerce webhook: error dispatching topic '%s' for instance '%s'",
                topic, instance.name,
            )
            return Response('Internal Error', status=500)

        return Response('OK', status=200)

    # -------------------------------------------------------------------------
    # Webhook Endpoints
    # -------------------------------------------------------------------------

    @http.route(
        '/woo/webhook/order',
        type='http', auth='none', csrf=False, methods=['POST'],
        save_session=False,
    )
    def webhook_order(self, **kw):
        """Receive order.created / order.updated from WooCommerce."""

        def dispatch(instance, data, topic):
            _logger.info(
                "WooCommerce order webhook received. Instance: %s, Topic: %s, Order ID: %s",
                instance.name, topic, data.get('id'),
            )
            if hasattr(instance, '_sync_order_from_wc'):
                instance._sync_order_from_wc(data)

        return self._verify_and_dispatch(dispatch)

    @http.route(
        '/woo/webhook/product',
        type='http', auth='none', csrf=False, methods=['POST'],
        save_session=False,
    )
    def webhook_product(self, **kw):
        """Receive product.updated from WooCommerce."""

        def dispatch(instance, data, topic):
            _logger.info(
                "WooCommerce product webhook received. Instance: %s, Topic: %s, Product ID: %s",
                instance.name, topic, data.get('id'),
            )
            if hasattr(instance, '_sync_product_from_wc'):
                instance._sync_product_from_wc(data)

        return self._verify_and_dispatch(dispatch)

    @http.route(
        '/woo/webhook/customer',
        type='http', auth='none', csrf=False, methods=['POST'],
        save_session=False,
    )
    def webhook_customer(self, **kw):
        """Receive customer.created / customer.updated from WooCommerce."""

        def dispatch(instance, data, topic):
            _logger.info(
                "WooCommerce customer webhook received. Instance: %s, Topic: %s, Customer ID: %s",
                instance.name, topic, data.get('id'),
            )
            if hasattr(instance, '_sync_customer_from_wc'):
                instance._sync_customer_from_wc(data)

        return self._verify_and_dispatch(dispatch)
