from unittest.mock import patch

from django.test import Client, TestCase, override_settings
from django.urls import reverse

from .models import Contact
from .seo import SERVICE_URL_NAMES, get_service_entries


@override_settings(
    DEBUG=True,
    EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend",
)
class ContactViewTests(TestCase):
    def setUp(self):
        self.client = Client()
        self.url = reverse("contact")
        self.valid_payload = {
            "name": "Jane Doe",
            "email": "jane@example.com",
            "subject": "Automation inquiry",
            "message": "We need help automating our workflow.",
        }

    def test_contact_get_renders_form(self):
        response = self.client.get(self.url)

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Send Us a Message")
        self.assertContains(response, 'id="contact-name"')
        self.assertContains(response, 'for="contact-name"')
        self.assertContains(response, 'id="contact-email"')
        self.assertContains(response, 'for="contact-email"')
        self.assertContains(response, 'id="contact-subject"')
        self.assertContains(response, 'for="contact-subject"')
        self.assertContains(response, 'id="contact-message"')
        self.assertContains(response, 'for="contact-message"')

    @patch("public.views.send_contact_email")
    def test_contact_post_success_saves_contact_and_sends_email(self, mock_send_email):
        response = self.client.post(self.url, self.valid_payload)

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "We'll be in contact shortly!")

        contact = Contact.objects.get()
        self.assertEqual(contact.name, "Jane Doe")
        self.assertEqual(contact.email, "jane@example.com")
        self.assertEqual(contact.subject, "Automation inquiry")
        self.assertEqual(contact.blurb, "We need help automating our workflow.")
        self.assertFalse(contact.contacted)

        mock_send_email.assert_called_once_with(
            "jane@example.com",
            "Automation inquiry",
            "We need help automating our workflow.",
        )

    @patch("public.views.send_contact_email")
    def test_contact_post_without_message_still_succeeds(self, mock_send_email):
        payload = {**self.valid_payload, "message": ""}

        response = self.client.post(self.url, payload)

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "We'll be in contact shortly!")
        self.assertEqual(Contact.objects.count(), 1)
        self.assertEqual(Contact.objects.get().blurb, "")
        mock_send_email.assert_called_once()

    def test_contact_post_missing_name_shows_error(self):
        payload = {**self.valid_payload, "name": ""}

        response = self.client.post(self.url, payload)

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Name is required")
        self.assertEqual(Contact.objects.count(), 0)

    def test_contact_post_missing_email_shows_error(self):
        payload = {**self.valid_payload, "email": ""}

        response = self.client.post(self.url, payload)

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Email is required")
        self.assertEqual(Contact.objects.count(), 0)

    def test_contact_post_missing_name_and_email_shows_error(self):
        payload = {**self.valid_payload, "name": "", "email": ""}

        response = self.client.post(self.url, payload)

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Both name and email are required")
        self.assertEqual(Contact.objects.count(), 0)

    def test_contact_post_missing_subject_does_not_save(self):
        payload = {**self.valid_payload, "subject": ""}

        response = self.client.post(self.url, payload)

        self.assertEqual(response.status_code, 200)
        self.assertNotContains(response, "We'll be in contact shortly!")
        self.assertEqual(Contact.objects.count(), 0)

    @override_settings(DEBUG=False)
    @patch("public.views.FormWithCaptcha.is_valid", return_value=False)
    def test_contact_post_invalid_captcha_shows_error(self, _mock_is_valid):
        response = self.client.post(self.url, self.valid_payload)

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "There was an error submitting. Try again")
        self.assertEqual(Contact.objects.count(), 0)


@override_settings(DEBUG=True, TIANJI_ENABLED=True)
class TianjiTrackingTests(TestCase):
    def test_homepage_includes_analytics_notice_when_enabled(self):
        response = self.client.get(reverse("public_index"))

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "cookie-consent-banner")
        self.assertContains(response, "cookie-consent-acknowledge")
        self.assertContains(response, "Acknowledge")
        self.assertNotContains(response, "cookie-consent-decline")
        self.assertNotContains(response, "Accept Analytics")
        self.assertContains(response, "tianji-config")
        self.assertContains(response, "tianji-consent.js")

    @override_settings(TIANJI_ENABLED=False)
    def test_homepage_omits_analytics_notice_when_disabled(self):
        response = self.client.get(reverse("public_index"))

        self.assertEqual(response.status_code, 200)
        self.assertNotContains(response, "cookie-consent-banner")
        self.assertNotContains(response, "tianji-config")


class AgenticBrowsingSeoTests(TestCase):
    def test_robots_txt_is_available(self):
        response = self.client.get(reverse("robots_txt"))

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response["Content-Type"], "text/plain; charset=utf-8")
        self.assertContains(response, "User-agent: *")
        self.assertContains(response, "Sitemap:")

    def test_sitemap_xml_lists_public_pages(self):
        response = self.client.get(reverse("sitemap_xml"))

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response["Content-Type"], "application/xml; charset=utf-8")
        self.assertContains(response, "<urlset")
        self.assertContains(response, reverse("contact"))
        self.assertContains(response, reverse("forward_deployed"))

    def test_llms_txt_is_available(self):
        response = self.client.get(reverse("llms_txt"))

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response["Content-Type"], "text/plain; charset=utf-8")
        self.assertContains(response, "# AI ML Operations, LLC")
        self.assertContains(response, "## Key pages")
        self.assertContains(response, reverse("contact"))

    def test_homepage_uses_semantic_nav_controls(self):
        response = self.client.get(reverse("public_index"))

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'id="services-menu-button"')
        self.assertContains(response, 'aria-haspopup="true"')
        self.assertContains(response, 'aria-label="Main navigation"')


@override_settings(DEBUG=True, WEBMCP_ENABLED=True)
class WebMcpTests(TestCase):
    def test_homepage_includes_webmcp_when_enabled(self):
        response = self.client.get(reverse("public_index"))

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "webmcp-config")
        self.assertContains(response, "webmcp-tools.js")
        self.assertContains(response, 'data-page-name="public_index"')
        self.assertContains(response, "forward_deployed")

    @override_settings(WEBMCP_ENABLED=False)
    def test_homepage_omits_webmcp_when_disabled(self):
        response = self.client.get(reverse("public_index"))

        self.assertEqual(response.status_code, 200)
        self.assertNotContains(response, "webmcp-config")
        self.assertNotContains(response, "webmcp-tools.js")

    def test_contact_page_includes_webmcp_form_annotations(self):
        response = self.client.get(reverse("contact"))

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'toolname="submit_contact_inquiry"')
        self.assertContains(response, "tooldescription=")
        self.assertContains(response, "submit_contact_inquiry")

    def test_webmcp_services_json_includes_all_service_pages(self):
        response = self.client.get(reverse("public_index"))

        self.assertEqual(response.status_code, 200)
        for slug in SERVICE_URL_NAMES:
            self.assertContains(response, slug)

    def test_service_entries_match_public_seo_config(self):
        entries = get_service_entries()
        self.assertEqual(len(entries), len(SERVICE_URL_NAMES))
        self.assertEqual({entry["slug"] for entry in entries}, SERVICE_URL_NAMES)

    def test_webmcp_static_script_defines_expected_tools(self):
        from pathlib import Path

        script_path = Path(__file__).resolve().parent / "static/public/js/webmcp-tools.js"
        script = script_path.read_text(encoding="utf-8")

        for tool_name in (
            "list_services",
            "get_page_content",
            "navigate_to_service",
            "open_contact_with_subject",
            "submit_contact_inquiry",
        ):
            self.assertIn("name: '" + tool_name + "'", script)

        self.assertIn("readOnlyHint: true", script)
        self.assertIn("readOnlyHint: false", script)
        self.assertIn("navigator.modelContext || document.modelContext", script)
