from apps.modules import services as modules
from apps.crm.models import Customer, Interaction
from tests.base import CoreTestCase

URL = "/api/v1/crm/customers/"


class CrmTests(CoreTestCase):
    def setUp(self):
        super().setUp()
        modules.enable_module(actor=self.root, organization=self.org_a, module_code="crm")
        self.mgr = self.api(self.manager_a, self.org_a)
        self.emp = self.api(self.employee_a, self.org_a)

    def make(self, client, **data):
        return client.post(URL, {"name": "Acme", **data}, format="json")

    def test_employee_owns_own_customers_only(self):
        r = self.make(self.emp, name="mine")
        self.assertEqual(r.status_code, 201)
        self.assertEqual(r.data["owner"]["id"], self.employee_a.pk)
        self.make(self.mgr, name="boss")
        self.assertEqual([c["name"] for c in self.emp.get(URL).data["results"]], ["mine"])
        self.assertEqual(self.mgr.get(URL).data["count"], 2)

    def test_employee_gets_404_on_foreign_customer(self):
        pk = self.make(self.mgr, name="boss").data["id"]
        self.assertEqual(self.emp.get(f"{URL}{pk}/").status_code, 404)
        self.assertEqual(self.emp.patch(f"{URL}{pk}/", {"status": "active"}, format="json").status_code, 404)
        self.assertEqual(self.emp.get(f"{URL}{pk}/interactions/").status_code, 404)
        body = {"type": "call", "summary": "x", "occurred_on": "2025-01-01"}
        self.assertEqual(self.emp.post(f"{URL}{pk}/interactions/", body, format="json").status_code, 404)

    def test_assignment_rules(self):
        self.assertEqual(self.make(self.emp, owner=self.manager_a.pk).status_code, 403)
        pk = self.make(self.mgr, owner=self.employee_a.pk).data["id"]
        self.assertEqual(self.emp.get(f"{URL}{pk}/").status_code, 200)  # now owner
        self.assertEqual(self.emp.patch(f"{URL}{pk}/", {"owner": self.manager_a.pk}, format="json").status_code, 403)
        self.assertEqual(self.make(self.mgr, owner=self.employee_b.pk).status_code, 400)  # other org
        self.assertEqual(self.emp.get(f"{URL}owners/".replace("customers/", "")).status_code, 403)

    def test_delete_needs_organization_scope(self):
        pk = self.make(self.emp).data["id"]
        self.assertEqual(self.emp.delete(f"{URL}{pk}/").status_code, 403)
        self.assertEqual(self.mgr.delete(f"{URL}{pk}/").status_code, 204)
        self.assertEqual(Customer.objects.count(), 0)

    def test_interactions_lifecycle_and_validation(self):
        pk = self.make(self.emp).data["id"]
        body = {"type": "call", "summary": "talked", "occurred_on": "2025-01-10", "follow_up_on": "2025-01-20"}
        r = self.emp.post(f"{URL}{pk}/interactions/", body, format="json")
        self.assertEqual(r.status_code, 201)
        self.assertEqual(len(self.emp.get(f"{URL}{pk}/interactions/").data), 1)
        bad = {**body, "follow_up_on": "2025-01-01"}
        self.assertEqual(self.emp.post(f"{URL}{pk}/interactions/", bad, format="json").status_code, 400)
        self.assertEqual(self.emp.post(f"{URL}{pk}/interactions/", {**body, "type": "zzz"}, format="json").status_code, 400)
        self.assertEqual(self.emp.post(f"{URL}{pk}/interactions/", {**body, "summary": " "}, format="json").status_code, 400)
        self.assertEqual(self.emp.delete(f"/api/v1/crm/interactions/{r.data['id']}/").status_code, 204)
        self.assertEqual(Interaction.objects.count(), 0)

    def test_search_filter_and_validation(self):
        self.make(self.mgr, name="Alpha Co", status="active", phone="0912")
        self.make(self.mgr, name="Beta", status="lead")
        self.assertEqual(self.mgr.get(URL, {"status": "active"}).data["count"], 1)
        self.assertEqual(self.mgr.get(URL, {"search": "0912"}).data["count"], 1)
        self.assertEqual(self.make(self.mgr, name=" ").status_code, 400)
        self.assertEqual(self.make(self.mgr, status="zzz").status_code, 400)

    def test_tenant_isolation_and_module_gate(self):
        pk = self.make(self.mgr).data["id"]
        self.assertEqual(self.api(self.manager_b, self.org_b).get(URL).status_code, 403)  # module off in B
        modules.enable_module(actor=self.root, organization=self.org_b, module_code="crm")
        other = self.api(self.manager_b, self.org_b)
        self.assertEqual(other.get(f"{URL}{pk}/").status_code, 404)
        self.assertEqual(other.delete(f"{URL}{pk}/").status_code, 404)
        modules.disable_module(actor=self.root, organization=self.org_a, module_code="crm")
        self.assertEqual(self.mgr.get(URL).status_code, 403)
        self.assertEqual(Customer.objects.count(), 1)  # data kept

    def test_interaction_of_another_org_is_404(self):
        pk = self.make(self.mgr).data["id"]
        iid = self.mgr.post(f"{URL}{pk}/interactions/", {"type": "note", "summary": "s", "occurred_on": "2025-01-01"}, format="json").data["id"]
        modules.enable_module(actor=self.root, organization=self.org_b, module_code="crm")
        self.assertEqual(self.api(self.manager_b, self.org_b).delete(f"/api/v1/crm/interactions/{iid}/").status_code, 404)

    def test_employee_cannot_delete_interaction_of_foreign_customer(self):
        pk = self.make(self.mgr).data["id"]
        iid = self.mgr.post(f"{URL}{pk}/interactions/", {"type": "note", "summary": "s", "occurred_on": "2025-01-01"}, format="json").data["id"]
        self.assertEqual(self.emp.delete(f"/api/v1/crm/interactions/{iid}/").status_code, 404)
        self.assertEqual(Interaction.objects.count(), 1)
    def test_last_contact_date_and_time(self):
        pk = self.make(self.emp, name="lc").data["id"]
        self.assertIsNone(self.emp.get(f"{URL}{pk}/").data["last_contact_on"])
        post = lambda d, t: self.emp.post(f"{URL}{pk}/interactions/", {"type": "call", "summary": "s", "occurred_on": d, "occurred_time": t}, format="json")
        self.assertEqual(post("2025-03-01", "09:30").status_code, 201)
        post("2025-03-01", "14:15")
        post("2025-02-20", "18:00")
        row = self.emp.get(URL).data["results"][0]
        self.assertEqual((row["last_contact_on"], row["last_contact_time"]), ("2025-03-01", "14:15"))
        detail = self.emp.get(f"{URL}{pk}/").data
        self.assertEqual((detail["last_contact_on"], detail["last_contact_time"]), ("2025-03-01", "14:15"))
        self.assertEqual(self.emp.get(f"{URL}{pk}/interactions/").data[0]["occurred_time"], "14:15:00")
        self.assertEqual(post("2025-03-02", "25:99").status_code, 400)