"""Shadow-Modus: entscheidet und protokolliert, führt nie aus; echte Absender-/Chat-IDs."""
import json
import os
import subprocess
import sys
import unittest
from pathlib import Path

from aria_router.config import load_gateway_config, parse_gateway_config
from aria_router.gateway import Gateway, Handling

from tests.helpers import OWNER_ID, GatewayTestCase, config_dict, photo

PACKAGE_ROOT = Path(__file__).resolve().parents[1]


class ShadowTests(GatewayTestCase):
    def test_shadow_logs_real_ids(self):
        gateway = self.gateway()
        result = gateway.shadow(self.request(42, "#public analyse"))
        self.assertEqual((result.handling, result.planned_handling), (Handling.SHADOW_DECISION, "reply"))
        record = self.decision_records(gateway)[-1]
        self.assertEqual((record["sender_id"], record["chat_id"], record["message_id"]), (OWNER_ID, OWNER_ID, 42))
        self.assertTrue(record["shadow"])
        self.assertEqual(record["routing"]["selected"], "codex")
        self.assertNotIn("test-user", json.dumps(record))

    def test_shadow_never_executes(self):
        gateway = self.gateway()
        for message_id, text in ((1, "#public a"), (2, "hallo"), (3, "Angebot BMW"), (4, "/codex #public b")):
            self.assertFalse(gateway.shadow(self.request(message_id, text)).delivered)
        self.assertEqual(gateway.adapters["codex"].runner.calls, [])
        self.assertEqual(self.sink.delivered, [])
        self.assertFalse((self.root / "state" / "nonces.json").exists())
        self.assertEqual(gateway.status()["backends"]["codex"]["budget"]["jobs"], 0)
        self.assertEqual(gateway.status()["backends"]["claude"]["budget"]["jobs"], 0)

    def test_shadow_log_has_no_plaintext(self):
        gateway = self.gateway()
        marker = "GEHEIMTEXT-7f3a9c"
        gateway.shadow(self.request(5, f"#public {marker}", attachments=[photo()]))
        gateway.handle(self.request(6, f"{marker} zweites mal"))
        raw = (self.root / "state" / "decisions.jsonl").read_text(encoding="utf-8")
        self.assertNotIn(marker, raw)
        record = self.decision_records(gateway)[0]
        self.assertEqual(record["prompt_chars"], len(f"#public {marker}"))
        self.assertEqual(len(record["prompt_sha256"]), 64)

    def test_shadow_state_separate_from_execute(self):
        gateway = self.gateway()
        gateway.shadow(self.request(7, "/claude"))
        self.assertEqual(gateway.handle(self.request(8, "#public x")).backend, "codex")
        self.assertEqual(gateway.shadow(self.request(9, "#public x")).backend, "claude")
        # Gleiche message_id: Shadow-Dedupe blockiert die echte Ausführung nicht.
        self.assertEqual(gateway.handle(self.request(9, "#public x")).handling, Handling.REPLY)

    def test_shadow_matches_handle(self):
        texts = ["#public Bitte debug mein Python", "hallo", "Angebot BMW", "/codex Angebot BMW", "/status",
                 "/something"]
        shadow_gw = self.gateway()
        for index, text in enumerate(texts, 100):
            shadow = shadow_gw.shadow(self.request(index, text))
            handled = shadow_gw.handle(self.request(index, text))
            with self.subTest(text=text):
                self.assertEqual(shadow.backend, handled.backend)
                self.assertEqual(shadow.planned_handling, handled.handling.value)

    def test_shadow_mode_disabled_in_config(self):
        gateway = self.gateway({"allowed_modes": ["execute"]})
        result = gateway.shadow(self.request(10, "hallo"))
        self.assertEqual((result.handling, result.code), (Handling.ERROR, "MODE_NOT_ENABLED"))

    def test_execute_disabled_in_example_config(self):
        example = json.loads((PACKAGE_ROOT / "config" / "gateway.example.json").read_text(encoding="utf-8"))
        example["state_dir"] = str(self.root / "state")
        example["clearance"]["key_file"] = str(self.root / "keys" / "clearance.key")
        example["auth"] = {"allowed_sender_ids": [OWNER_ID]}
        gateway = Gateway(parse_gateway_config(example), clock=self.clock)
        self.assertEqual(gateway.handle(self.request(11, "hallo")).code, "MODE_NOT_ENABLED")
        self.assertEqual(gateway.shadow(self.request(12, "hallo")).handling, Handling.SHADOW_DECISION)

    def test_legacy_shadow_cli_fails_closed(self):
        env = {"PATH": "/usr/bin:/bin", "PYTHONPATH": str(PACKAGE_ROOT)}
        for payload in (json.dumps({"text": "hallo"}).encode(), json.dumps({"text": '"' * 65536}).encode(),
                        b"{kaputt"):
            proc = subprocess.run([sys.executable, "-m", "aria_router.shadow_cli"], input=payload, cwd=PACKAGE_ROOT,
                                  env=env, capture_output=True, timeout=30)
            self.assertEqual(proc.returncode, 0)
            result = json.loads(proc.stdout)
            self.assertEqual(result["handling"], "drop")
            self.assertIsNone(result["backend"])
            self.assertFalse(result["delivered"])
        self.assertEqual(json.loads(subprocess.run(
            [sys.executable, "-m", "aria_router.shadow_cli"], input=json.dumps({"text": "x"}).encode(),
            cwd=PACKAGE_ROOT, env=env, capture_output=True, timeout=30).stdout)["reason"],
            "MISSING_TRANSPORT_IDENTITY")


if __name__ == "__main__":
    unittest.main()
