"""Stability and API hardening tests for v1.0."""

from __future__ import annotations

import importlib
import os
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch

import yaml

from tests.test_helpers import base_config

try:  # pragma: no cover
    from fastapi.testclient import TestClient
except ImportError:  # pragma: no cover
    TestClient = None


@unittest.skipIf(TestClient is None, "fastapi not installed in this environment")
class StabilityApiTest(unittest.TestCase):
    """Validate non-crashing behavior and stable API contracts."""

    @classmethod
    def setUpClass(cls) -> None:
        """Initialize API app with isolated workspace for stability tests."""
        cls._tempdir = tempfile.TemporaryDirectory()
        root = Path(cls._tempdir.name)
        workspace = root / "workspace"
        config_path = root / "config.yaml"

        config = base_config()
        config["workspace"]["root"] = str(workspace)
        config["workspace"]["reports_dir"] = str(workspace / "reports")
        config["klytics"] = {"enabled": False, "webhook_url": "", "lead_threshold": 60}
        config["email"]["smtp"]["host"] = "localhost"
        config["email"]["smtp"]["username"] = "test"
        config["email"]["smtp"]["password"] = "test"

        with config_path.open("w", encoding="utf-8") as handle:
            yaml.safe_dump(config, handle)

        os.environ["KIESSCLAW_CONFIG"] = str(config_path)
        import kiessclaw.api.app as api_app

        cls.api = importlib.reload(api_app)
        cls.client = TestClient(cls.api.app)

    @classmethod
    def tearDownClass(cls) -> None:
        """Dispose temp workspace."""
        cls._tempdir.cleanup()

    def setUp(self) -> None:
        """Reset collections between stability test cases."""
        memory = self.api.CONTEXT.memory
        for collection in [
            "accounts",
            "contacts",
            "segments",
            "sequences",
            "enrollments",
            "messages",
            "replies",
            "analytics",
            "seo_audits",
            "waitlist",
        ]:
            memory.save_data(collection, [])

    def test_post_audit_invalid_url_returns_422(self) -> None:
        """Audit requests with invalid URL formats should fail validation with 422."""
        response = self.client.post("/audit", json={"url": "not-a-url", "auto_enroll": False})
        self.assertEqual(422, response.status_code)
        body = response.json()
        self.assertIn("error", body)

    def test_post_contacts_missing_email_returns_422(self) -> None:
        """Contacts endpoint should enforce required email field and return 422."""
        response = self.client.post(
            "/contacts",
            json={"first_name": "No", "last_name": "Email"},
        )
        self.assertEqual(422, response.status_code)
        body = response.json()
        self.assertIn("error", body)

    def test_get_version_returns_expected_string(self) -> None:
        """Version endpoint should return API semantic version string."""
        response = self.client.get("/version")
        self.assertEqual(200, response.status_code)
        body = response.json()
        self.assertEqual("1.5.0", body.get("version"))
        self.assertIn("agents_loaded", body)
        self.assertIn("uptime_seconds", body)

    def test_get_health_returns_all_agent_names(self) -> None:
        """Health endpoint should expose all 10 expected agent codenames."""
        response = self.client.get("/health")
        self.assertEqual(200, response.status_code)
        body = response.json()
        agents = set(body.get("agents", {}).keys())
        expected = {"KPRO", "KSEQ", "KPEN", "KINB", "KMET", "KRAWL", "KANA", "KWRI", "KSCO", "KREP"}
        self.assertEqual(expected, agents)

    def test_agent_failure_returns_error_payload(self) -> None:
        """Internal agent runtime failures should return JSON error payload, not uncaught exception."""
        with patch.object(self.api.CONTEXT.pipeline, "run_audit", side_effect=RuntimeError("forced boom")):
            response = self.client.post("/audit", json={"url": "https://example.com", "auto_enroll": False})
        self.assertEqual(502, response.status_code)
        body = response.json()
        self.assertIn("error", body)
        self.assertIn("forced boom", body["error"])


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