# -*- coding: utf-8 -*-
"""Location: ./tests/unit/mcpgateway/utils/test_security_cookies.py
Copyright 2026
SPDX-License-Identifier: Apache-2.0
Authors: Mihai Criveti

Unit tests for mcpgateway.utils.security_cookies.
"""

# Standard
import logging
from types import SimpleNamespace

# Third-Party
from fastapi import Response
import pytest

# First-Party
import mcpgateway.utils.security_cookies as security_cookies


def test_set_auth_cookie_uses_short_expiry_and_insecure_in_dev(monkeypatch) -> None:
    monkeypatch.setattr(
        security_cookies,
        "settings",
        SimpleNamespace(environment="development", secure_cookies=False, cookie_samesite="lax", app_root_path=""),
    )

    resp = Response()
    security_cookies.set_auth_cookie(resp, token="tok123", remember_me=False)

    header = resp.headers.get("set-cookie") or ""
    assert "jwt_token=tok123" in header
    assert "Max-Age=3600" in header
    assert "Path=/" in header
    assert "HttpOnly" in header
    assert "Secure" not in header


def test_set_auth_cookie_remember_me_sets_long_expiry_and_secure_in_production(monkeypatch) -> None:
    monkeypatch.setattr(
        security_cookies,
        "settings",
        SimpleNamespace(environment="production", secure_cookies=False, cookie_samesite="strict", app_root_path="/mcp"),
    )

    resp = Response()
    security_cookies.set_auth_cookie(resp, token="tok123", remember_me=True)

    header = resp.headers.get("set-cookie") or ""
    assert "Max-Age=2592000" in header  # 30 days
    assert "Path=/mcp" in header
    assert "SameSite=strict" in header
    assert "Secure" in header


def test_clear_auth_cookie_uses_same_security_attributes(monkeypatch) -> None:
    monkeypatch.setattr(
        security_cookies,
        "settings",
        SimpleNamespace(environment="production", secure_cookies=False, cookie_samesite="lax", app_root_path=""),
    )

    resp = Response()
    security_cookies.set_auth_cookie(resp, token="tok123", remember_me=False)
    security_cookies.clear_auth_cookie(resp)

    # Starlette appends a second Set-Cookie header for the deletion.
    set_cookies = resp.headers.getlist("set-cookie")
    assert any("jwt_token=" in c for c in set_cookies)
    assert any("Secure" in c for c in set_cookies)


def test_session_cookie_set_and_clear(monkeypatch) -> None:
    monkeypatch.setattr(
        security_cookies,
        "settings",
        SimpleNamespace(environment="development", secure_cookies=True, cookie_samesite="lax", app_root_path="/"),
    )

    resp = Response()
    security_cookies.set_session_cookie(resp, session_id="sess-1", max_age=60)
    security_cookies.clear_session_cookie(resp)

    set_cookies = resp.headers.getlist("set-cookie")
    assert any("session_id=sess-1" in c for c in set_cookies)
    assert any("session_id=" in c for c in set_cookies)  # deletion cookie
    assert any("Max-Age=60" in c for c in set_cookies)
    assert any("Secure" in c for c in set_cookies)


def test_set_auth_cookie_best_effort_sub_extraction_swallows_decode_errors(monkeypatch) -> None:
    """If the token looks like a JWT but is not decodable, we still set the cookie."""
    monkeypatch.setattr(
        security_cookies,
        "settings",
        SimpleNamespace(environment="development", secure_cookies=False, cookie_samesite="lax", app_root_path=""),
    )

    resp = Response()
    # Second segment is intentionally not valid base64/json, triggering the best-effort except block.
    security_cookies.set_auth_cookie(resp, token="header..sig", remember_me=False)

    header = resp.headers.get("set-cookie") or ""
    assert "jwt_token=header..sig" in header


def test_set_auth_cookie_warns_when_cookie_approaches_limit(monkeypatch, caplog) -> None:
    monkeypatch.setattr(
        security_cookies,
        "settings",
        SimpleNamespace(environment="development", secure_cookies=False, cookie_samesite="lax", app_root_path=""),
    )
    monkeypatch.setattr(security_cookies, "_COOKIE_WARN_THRESHOLD", 1)

    resp = Response()
    with caplog.at_level(logging.WARNING, logger=security_cookies.logger.name):
        security_cookies.set_auth_cookie(resp, token="tok123", remember_me=False)

    assert any("approaching" in rec.message for rec in caplog.records)


def test_set_auth_cookie_raises_when_cookie_exceeds_hard_limit(monkeypatch) -> None:
    monkeypatch.setattr(
        security_cookies,
        "settings",
        SimpleNamespace(environment="development", secure_cookies=False, cookie_samesite="lax", app_root_path=""),
    )

    with pytest.raises(security_cookies.CookieTooLargeError):
        security_cookies.set_auth_cookie(Response(), token="x" * 5000, remember_me=False)
