from django.contrib.auth.models import User
from django.core import mail
from django.test import TestCase, override_settings
from django.urls import reverse

from apps.accounts.models import ClientProfile
from apps.projects.models import ProjectBrief, ProjectInternalNote


class ProjectPortalTest(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(
            username="client",
            email="client@example.com",
            password="Str0ngPass!word",
            first_name="Client",
            last_name="User",
        )
        ClientProfile.objects.create(user=self.user)
        self.other = User.objects.create_user(
            username="other",
            email="other@example.com",
            password="Str0ngPass!word",
        )
        ClientProfile.objects.create(user=self.other)

    def _brief_payload(self):
        return {
            "title": "Radiomics pipeline",
            "category": ProjectBrief.CATEGORY_MEDICAL_IMAGING,
            "description": "Need a standardized radiomics workflow.",
            "budget_range": ProjectBrief.BUDGET_5K_15K,
            "desired_deadline": "2026-12-31",
            "reference_links": "https://example.com/spec",
        }

    def _create_brief(self, **overrides):
        defaults = dict(
            client=self.user,
            title="Brief",
            category=ProjectBrief.CATEGORY_WEB,
            description="d",
            budget_range=ProjectBrief.BUDGET_UNDER_5K,
        )
        defaults.update(overrides)
        return ProjectBrief.objects.create(**defaults)

    def test_dashboard_requires_login(self):
        response = self.client.get(reverse("projects:dashboard"))
        self.assertEqual(response.status_code, 302)

    def test_create_brief_sends_admin_email(self):
        self.client.login(username="client", password="Str0ngPass!word")
        with override_settings(MANAGED_PROJECTS_NOTIFY_EMAILS="ops@tecvico.com"):
            response = self.client.post(reverse("projects:create"), data=self._brief_payload())
        self.assertEqual(response.status_code, 302)
        brief = ProjectBrief.objects.get(title="Radiomics pipeline")
        self.assertEqual(brief.client, self.user)
        self.assertEqual(brief.status, ProjectBrief.STATUS_SUBMITTED)
        self.assertEqual(len(mail.outbox), 1)
        self.assertIn("Radiomics pipeline", mail.outbox[0].subject)
        self.assertIn("ops@tecvico.com", mail.outbox[0].to)

    def test_create_brief_with_title_only(self):
        self.client.login(username="client", password="Str0ngPass!word")
        response = self.client.post(
            reverse("projects:create"),
            data={"title": "Minimal brief"},
        )
        self.assertEqual(response.status_code, 302)
        brief = ProjectBrief.objects.get(title="Minimal brief")
        self.assertEqual(brief.description, "")
        self.assertEqual(brief.category, "")
        self.assertEqual(brief.budget_range, "")

    def test_create_brief_requires_title(self):
        self.client.login(username="client", password="Str0ngPass!word")
        response = self.client.post(reverse("projects:create"), data={"title": ""})
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "This field is required")
        self.assertEqual(ProjectBrief.objects.count(), 0)

    def test_create_renders_submit_only_on_last_step(self):
        self.client.login(username="client", password="Str0ngPass!word")
        response = self.client.get(reverse("projects:create"))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'data-wizard-submit hidden')
        self.assertContains(response, 'data-wizard-next')
        self.assertNotContains(response, 'data-wizard-submit">{{ submit_label }}</button>')

    def test_dashboard_lists_only_own_briefs(self):
        self._create_brief(title="Mine")
        self._create_brief(client=self.other, title="Not mine")
        self.client.login(username="client", password="Str0ngPass!word")
        response = self.client.get(reverse("projects:dashboard"))
        self.assertEqual(response.status_code, 200)
        titles = [brief.title for brief in response.context["briefs"]]
        self.assertEqual(titles, ["Mine"])

    def test_edit_allowed_only_when_submitted(self):
        brief = self._create_brief(
            title="Editable",
            category=ProjectBrief.CATEGORY_DATA,
            budget_range=ProjectBrief.BUDGET_NOT_SURE,
            status=ProjectBrief.STATUS_SUBMITTED,
        )
        self.client.login(username="client", password="Str0ngPass!word")
        response = self.client.get(reverse("projects:edit", kwargs={"pk": brief.pk}))
        self.assertEqual(response.status_code, 200)

        brief.status = ProjectBrief.STATUS_UNDER_REVIEW
        brief.save()
        response = self.client.get(reverse("projects:edit", kwargs={"pk": brief.pk}))
        self.assertEqual(response.status_code, 302)

    def test_locked_project_blocks_edit(self):
        brief = self._create_brief(
            title="Locked",
            status=ProjectBrief.STATUS_SUBMITTED,
            locked=True,
        )
        self.client.login(username="client", password="Str0ngPass!word")
        response = self.client.get(reverse("projects:edit", kwargs={"pk": brief.pk}))
        self.assertEqual(response.status_code, 302)

    def test_locked_field_is_disabled_on_edit_form(self):
        brief = self._create_brief(
            title="Lock field",
            status=ProjectBrief.STATUS_SUBMITTED,
            lock_title=True,
        )
        self.client.login(username="client", password="Str0ngPass!word")
        response = self.client.get(reverse("projects:edit", kwargs={"pk": brief.pk}))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'name="title"')
        self.assertContains(response, "disabled")

    def test_locked_field_value_is_preserved_on_submit(self):
        brief = self._create_brief(
            title="Original title",
            status=ProjectBrief.STATUS_SUBMITTED,
            lock_title=True,
        )
        self.client.login(username="client", password="Str0ngPass!word")
        self.client.post(
            reverse("projects:edit", kwargs={"pk": brief.pk}),
            data={
                "title": "Hacked title",
                "category": brief.category,
                "description": brief.description,
                "budget_range": brief.budget_range,
                "desired_deadline": "",
                "reference_links": "",
            },
        )
        brief.refresh_from_db()
        self.assertEqual(brief.title, "Original title")

    def test_status_change_emails_client(self):
        brief = self._create_brief(
            title="Notify me",
            category=ProjectBrief.CATEGORY_RESEARCH,
            budget_range=ProjectBrief.BUDGET_15K_50K,
            status=ProjectBrief.STATUS_SUBMITTED,
        )
        mail.outbox.clear()
        brief.status = ProjectBrief.STATUS_UNDER_REVIEW
        brief.save()
        self.assertEqual(len(mail.outbox), 1)
        self.assertIn("client@example.com", mail.outbox[0].to)

    def test_internal_notes_not_on_detail_page(self):
        brief = self._create_brief(
            title="Secret notes",
            category=ProjectBrief.CATEGORY_OTHER,
        )
        ProjectInternalNote.objects.create(brief=brief, note="Internal only", author=self.other)
        self.client.login(username="client", password="Str0ngPass!word")
        response = self.client.get(reverse("projects:detail", kwargs={"pk": brief.pk}))
        self.assertEqual(response.status_code, 200)
        self.assertNotIn(b"Internal only", response.content)

    def test_website_notes_visible_on_detail_page(self):
        brief = self._create_brief(
            title="Public notes",
            category=ProjectBrief.CATEGORY_WEB,
            website_notes="Your kickoff call is scheduled for next week.",
        )
        self.client.login(username="client", password="Str0ngPass!word")
        response = self.client.get(reverse("projects:detail", kwargs={"pk": brief.pk}))
        self.assertContains(response, "Notes from Tecvico")
        self.assertContains(response, "kickoff call is scheduled")

    def test_create_renders_wizard_steps(self):
        self.client.login(username="client", password="Str0ngPass!word")
        response = self.client.get(reverse("projects:create"))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "data-brief-wizard")
        self.assertContains(response, "Project basics")
        self.assertContains(response, "References &amp; files")

    def test_quote_visible_when_quoted(self):
        brief = self._create_brief(
            title="Quoted project",
            category=ProjectBrief.CATEGORY_WORKFLOW,
            budget_range=ProjectBrief.BUDGET_50K_PLUS,
            status=ProjectBrief.STATUS_QUOTED,
            quote_text="We can deliver in 8 weeks for $45,000.",
        )
        self.client.login(username="client", password="Str0ngPass!word")
        response = self.client.get(reverse("projects:detail", kwargs={"pk": brief.pk}))
        self.assertContains(response, "We can deliver in 8 weeks")
