# (c) cavaliba.com - tests / log2 - ambient context: reset, bind, aaa, request_started

from django.test import TestCase

from app_data.aaa import start_command
from app_home.log import log2, reset_on_request_started


class TestLog2Ambient(TestCase):
    def test_reset_replaces_and_sets_request_id(self):
        log2.reset(channel="web", actor="alice")
        first = log2.ambient()["request_id"]
        log2.reset(channel="api")
        ambient = log2.ambient()
        self.assertEqual(ambient["channel"], "api")
        self.assertEqual(ambient["actor"], "")
        self.assertTrue(ambient["request_id"])
        self.assertNotEqual(ambient["request_id"], first)

    def test_bind_merges(self):
        log2.reset(channel="web")
        log2.bind(actor="bob", origin=None)
        ambient = log2.ambient()
        self.assertEqual((ambient["channel"], ambient["actor"]), ("web", "bob"))

    def test_restore_token(self):
        log2.reset(channel="web", actor="outer")
        token = log2.reset(channel="celery", actor="inner")
        log2.restore(token)
        self.assertEqual(log2.ambient()["actor"], "outer")

    def test_bind_aaa_plain_user(self):
        log2.reset(channel="web")
        log2.bind_aaa({"username": "alice", "is_authenticated": True, "user_ip": "10.0.0.1"})
        ambient = log2.ambient()
        self.assertEqual(ambient["actor"], "alice")
        self.assertEqual(ambient["actor_effective"], "")
        self.assertEqual(ambient["actor_kind"], "user")
        self.assertEqual(ambient["client_ip"], "10.0.0.1")

    def test_bind_aaa_impersonation(self):
        log2.reset(channel="web")
        log2.bind_aaa({"username": "bob", "impersonate_by": "admin", "is_authenticated": True})
        ambient = log2.ambient()
        self.assertEqual((ambient["actor"], ambient["actor_effective"]), ("admin", "bob"))

    def test_bind_aaa_apikey_and_anonymous(self):
        log2.reset(channel="api")
        log2.bind_aaa({"username": "API:ops", "is_authenticated": True})
        self.assertEqual(log2.ambient()["actor_kind"], "apikey")
        log2.reset(channel="web")
        log2.bind_aaa({"username": "unknown", "is_authenticated": False})
        self.assertEqual(log2.ambient()["actor_kind"], "anonymous")

    def test_request_started_resets_previous_request(self):
        log2.reset(channel="web", actor="stale-user")
        reset_on_request_started(environ={
            "PATH_INFO": "/api/cmt/", "REMOTE_ADDR": "10.0.0.9", "HTTP_X_REQUEST_ID": "rid-1",
        })  # fmt: skip
        ambient = log2.ambient()
        self.assertEqual(ambient["channel"], "api")
        self.assertEqual(ambient["origin"], "/api/cmt/")
        self.assertEqual(ambient["actor"], "")
        self.assertEqual(ambient["client_ip"], "10.0.0.9")
        self.assertEqual(ambient["request_id"], "rid-1")

    def test_request_started_proxy_headers(self):
        reset_on_request_started(environ={"PATH_INFO": "/home/", "REMOTE_ADDR": "127.0.0.1",
                                          "HTTP_X_FORWARDED_FOR": "10.1.1.1, 10.2.2.2"})  # fmt: skip
        self.assertEqual(log2.ambient()["channel"], "web")
        self.assertEqual(log2.ambient()["client_ip"], "10.1.1.1")
        reset_on_request_started(environ={"PATH_INFO": "/", "HTTP_X_REAL_IP": "10.3.3.3",
                                          "HTTP_X_FORWARDED_FOR": "10.1.1.1"})  # fmt: skip
        self.assertEqual(log2.ambient()["client_ip"], "10.3.3.3")

    def test_enter_keeps_request_id_and_resets_actor(self):
        reset_on_request_started(environ={"PATH_INFO": "/home/", "REMOTE_ADDR": "10.0.0.9"})
        request_id = log2.ambient()["request_id"]
        log2.bind(actor="previous", actor_kind="user")
        log2.enter(channel="web", origin="log", domain="home", client_ip="10.0.0.9")
        ambient = log2.ambient()
        self.assertEqual(ambient["request_id"], request_id)
        self.assertEqual((ambient["origin"], ambient["domain"]), ("log", "home"))
        self.assertEqual((ambient["actor"], ambient["actor_kind"]), ("", ""))

    def test_enter_without_request_context_creates_request_id(self):
        log2.reset()
        log2.bind(request_id="")
        log2.enter(channel="api")
        self.assertTrue(log2.ambient()["request_id"])

    def test_bind_aaa_keeps_the_request_ip(self):
        log2.enter(channel="web", client_ip="10.2.2.2")
        log2.bind_aaa({"username": "alice", "is_authenticated": True, "user_ip": "10.1.1.1"})
        self.assertEqual(log2.ambient()["client_ip"], "10.2.2.2")

    def test_start_command_binds_cli(self):
        start_command(command="cavaliba", action="version")
        ambient = log2.ambient()
        self.assertEqual(ambient["channel"], "cli")
        self.assertEqual(ambient["origin"], "cavaliba version")
        self.assertEqual(ambient["actor_kind"], "system")
