"""FastAPI endpoint tests for KIESSCLAW service layer."""

from __future__ import annotations

import importlib
import os
import tempfile
import unittest
from pathlib import Path

import yaml

from tests.test_helpers import base_config

try:  # pragma: no cover - dependency availability varies by environment
    from fastapi.testclient import TestClient
except ImportError:  # pragma: no cover
    TestClient = None


@unittest.skipIf(TestClient is None, "fastapi not installed in this environment")
class ApiTest(unittest.TestCase):
    """Verify primary API contract endpoints for v0.3 service layer."""

    @classmethod
    def setUpClass(cls) -> None:
        """Initialize API app with isolated test workspace."""
        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["llm"]["provider"] = "ollama"
        config["llm"]["api_key"] = ""
        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 mutable collections before each API test."""
        memory = self.api.CONTEXT.memory
        for collection in [
            "accounts",
            "contacts",
            "segments",
            "sequences",
            "enrollments",
            "messages",
            "replies",
            "analytics",
            "seo_audits",
            "waitlist",
        ]:
            memory.save_data(collection, [])

    def _create_active_sequence(self) -> str:
        """Create and persist one active sequence for enrollment tests."""
        kseq = self.api.CONTEXT.registry["KSEQ"]
        sequence = kseq.sequence_skill.create_sequence(  # type: ignore[attr-defined]
            name="API Test Sequence",
            sender_email="sender@test.local",
            steps=[{"channel": "email", "delay_days": 0, "subject": "Hi {{first_name}}", "body": "Hello"}],
        )
        sequence["status"] = "active"
        memory = self.api.CONTEXT.memory
        memory.save_data("sequences", [sequence])
        return sequence["id"]

    def test_post_contacts_creates_contact(self) -> None:
        """POST /contacts should create and score a new contact."""
        response = self.client.post(
            "/contacts",
            json={
                "email": "api-user@example.com",
                "first_name": "Api",
                "last_name": "User",
                "title": "Head of Growth",
                "company": "Example Inc",
                "domain": "example.com",
            },
        )
        self.assertEqual(200, response.status_code)
        body = response.json()
        self.assertIn("contact_id", body)
        self.assertIn("icp_score", body)
        self.assertIn("qualified", body)

    def test_post_audit_returns_seo_score(self) -> None:
        """POST /audit should always return a numeric seo_score payload."""
        response = self.client.post("/audit", json={"url": "https://example.com", "auto_enroll": False})
        self.assertEqual(200, response.status_code)
        body = response.json()
        self.assertIn("domain", body)
        self.assertIn("seo_score", body)
        self.assertIsInstance(body["issues"], list)

    def test_post_reply_stops_sequence(self) -> None:
        """POST /reply should process intent and stop future sends for contact enrollments."""
        contact_resp = self.client.post(
            "/contacts",
            json={
                "email": "reply-user@example.com",
                "first_name": "Reply",
                "last_name": "User",
                "title": "VP Sales",
                "company": "Reply Co",
                "domain": "replyco.com",
            },
        )
        contact_id = contact_resp.json()["contact_id"]
        sequence_id = self._create_active_sequence()
        enroll_resp = self.client.post(f"/sequences/{sequence_id}/enroll", json={"contact_id": contact_id})
        self.assertEqual(200, enroll_resp.status_code)

        reply_resp = self.client.post(
            "/reply",
            json={"contact_id": contact_id, "text": "Please unsubscribe me from this list."},
        )
        self.assertEqual(200, reply_resp.status_code)
        body = reply_resp.json()
        self.assertEqual("unsubscribe", body["intent"])
        self.assertTrue(body["sequence_stopped"])

    def test_get_health_returns_all_agents(self) -> None:
        """GET /health should return a healthy status and all 10 loaded agents."""
        response = self.client.get("/health")
        self.assertEqual(200, response.status_code)
        body = response.json()
        self.assertEqual("ok", body["status"])
        self.assertEqual(10, len(body["agents"]))

    def test_get_pipeline_returns_funnel(self) -> None:
        """GET /pipeline should return contact + enrollment funnel structures."""
        response = self.client.get("/pipeline")
        self.assertEqual(200, response.status_code)
        body = response.json()
        self.assertIn("contacts", body)
        self.assertIn("enrollments", body)
        self.assertIn("funnel", body)

    def test_get_sequences_returns_list(self) -> None:
        """GET /sequences should return list payload."""
        self._create_active_sequence()
        response = self.client.get("/sequences")
        self.assertEqual(200, response.status_code)
        body = response.json()
        self.assertIsInstance(body, list)
        self.assertGreaterEqual(len(body), 1)

    def test_get_inbox_returns_list(self) -> None:
        """GET /inbox should return list payload."""
        response = self.client.get("/inbox")
        self.assertEqual(200, response.status_code)
        body = response.json()
        self.assertIsInstance(body, list)


class DashboardAssetTest(unittest.TestCase):
    """Validate dashboard asset exists for v0.4 UI deliverable."""

    def test_dashboard_file_contains_brand(self) -> None:
        """site/dashboard.html should exist and include KiessClaw brand text."""
        dashboard_path = Path(__file__).resolve().parent.parent / "site" / "dashboard.html"
        self.assertTrue(dashboard_path.exists())
        content = dashboard_path.read_text(encoding="utf-8")
        self.assertIn("KiessClaw", content)


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