"""Read the affiliate referrer key from the request and stash the
resolved widget config id in the session. The signup hook
(``res_users.create``) then persists it on the recruiter's partner so
the attribution survives the session.

* **First-touch** (URL ``?ref=KEY``) — the widget appends this on every
  job link click (kj_widget.js:2178, 2434). On arrival here we resolve
  it, write the session, and drop a long-lived ``kj_aff`` cookie on the
  KJ domain so a return visit without ``?ref`` still credits the
  affiliate. Cookie is first-party to KJ, so no cross-origin restriction.
* **Return visit** (``kj_aff`` cookie) — re-resolves and writes the
  session if it's empty.

V9 equivalent: job_board/models/ir_http.py:16-107 (cookie ``jb_iframe``).
"""

import logging

from odoo import models
from odoo.http import request

_logger = logging.getLogger(__name__)

# 1-year persistence — long enough to cover a recruiter that lands via
# an affiliate, signs up later, and publishes their first job weeks out.
_COOKIE_MAX_AGE = 365 * 24 * 3600


class IrHttp(models.AbstractModel):
    _inherit = "ir.http"

    @classmethod
    def _dispatch(cls, endpoint):
        aff_key = None
        try:
            aff_key = cls._kj_capture_affiliate_referrer()
        except Exception:
            # Attribution must never break a request.
            _logger.exception("Affiliate referrer capture failed")

        response = super()._dispatch(endpoint)

        # Only set the cookie when we just resolved a first-touch ?ref=
        # from the URL. Cookie-sourced keys are already on the browser.
        if aff_key and hasattr(response, "set_cookie"):
            try:
                response.set_cookie(
                    "kj_aff",
                    aff_key,
                    max_age=_COOKIE_MAX_AGE,
                    samesite="Lax",
                    httponly=False,
                )
            except Exception:
                _logger.exception("Failed to set kj_aff cookie")
        return response

    @classmethod
    def _kj_capture_affiliate_referrer(cls):
        """Resolve the affiliate referrer from the request and return the
        URL-sourced key (for cookie persistence). Returns None when no
        new attribution was established.
        """
        if not request:
            return None
        sess = request.session
        url_key = request.httprequest.args.get("ref") if request.httprequest else None
        cookie_key = (
            request.httprequest.cookies.get("kj_aff")
            if request.httprequest else None
        )
        aff_key = url_key or cookie_key
        if not aff_key:
            return None

        # First-touch wins. Only resolve & write the session when empty;
        # but always refresh the cookie when ?ref= is on the URL so the
        # most recent affiliate that the visitor opened wins on return.
        if sess.get("affiliate_widget_config_id") and not url_key:
            return None

        # widget_key is reused across modes for the same affiliate
        # (affiliate_widget_config.py:540-548), so limit=1 is safe.
        config = request.env["affiliate.widget.config"].sudo().search(
            [("widget_key", "=", aff_key), ("is_active", "=", True)],
            limit=1,
        )
        if not config:
            return None

        sess["affiliate_widget_config_id"] = config.id
        sess["affiliate_referrer_source"] = config.widget_mode or "kj"
        return url_key  # only the URL path triggers cookie re-set
