import datetime

from infrastructure.models import LeaveRequest
from tests.base import CoreTestCase

V1 = "/api/v1/attendance/leave-requests"
TODAY = datetime.date.today()


class LeaveReviewHistoryTests(CoreTestCase):
    def setUp(self):
        super().setUp()
        self.mgr = self.api(self.manager_a, self.org_a)
        self.emp = self.api(self.employee_a, self.org_a)

    def leave(self, date=TODAY):
        return LeaveRequest.objects.create(
            organization=self.org_a, user=self.employee_a, date=date, type="daily", category="annual"
        )

    def test_rejecting_requires_a_reason(self):
        lv = self.leave()
        self.assertEqual(self.mgr.post(f"{V1}/{lv.pk}/reject/").status_code, 400)
        self.assertEqual(self.mgr.post(f"{V1}/{lv.pk}/reject/", {"note": "   "}, format="json").status_code, 400)
        lv.refresh_from_db()
        self.assertEqual(lv.status, "pending")  # nothing changed
        r = self.mgr.post(f"{V1}/{lv.pk}/reject/", {"note": "Team is short that day"}, format="json")
        self.assertEqual(r.status_code, 200)
        self.assertEqual((r.data["status"], r.data["review_note"]), ("rejected", "Team is short that day"))

    def test_approving_may_carry_a_note_but_does_not_need_one(self):
        a, b = self.leave(), self.leave(date=TODAY + datetime.timedelta(days=1))
        self.assertIsNone(self.mgr.post(f"{V1}/{a.pk}/approve/").data["review_note"])
        r = self.mgr.post(f"{V1}/{b.pk}/approve/", {"note": "Enjoy"}, format="json")
        self.assertEqual(r.data["review_note"], "Enjoy")

    def test_history_shows_requester_reviewer_note_and_time(self):
        lv = self.leave()
        self.mgr.post(f"{V1}/{lv.pk}/reject/", {"note": "No cover"}, format="json")
        rows = self.mgr.get(f"{V1}/review/", {"status": "reviewed"}).data
        self.assertEqual(len(rows), 1)
        row = rows[0]
        self.assertEqual(row["user_name"], "employee-a")
        self.assertEqual(row["reviewed_by_name"], "manager-a")
        self.assertEqual(row["review_note"], "No cover")
        self.assertIsNotNone(row["reviewed_at"])

    def test_reviewed_filter_excludes_pending_and_keeps_the_pending_tab(self):
        pending, done = self.leave(), self.leave(date=TODAY + datetime.timedelta(days=2))
        self.mgr.post(f"{V1}/{done.pk}/approve/")
        reviewed = self.mgr.get(f"{V1}/review/", {"status": "reviewed"}).data
        self.assertEqual([r["id"] for r in reviewed], [done.pk])
        self.assertEqual([r["id"] for r in self.mgr.get(f"{V1}/review/", {"status": "pending"}).data], [pending.pk])
        self.assertEqual(len(self.mgr.get(f"{V1}/review/", {"status": "all"}).data), 2)

    def test_employee_sees_the_decision_and_reason_on_their_own_request(self):
        lv = self.leave()
        self.mgr.post(f"{V1}/{lv.pk}/reject/", {"note": "Not this week"}, format="json")
        mine = self.emp.get(f"{V1}/").data[0]
        self.assertEqual((mine["status"], mine["review_note"], mine["reviewed_by_name"]), ("rejected", "Not this week", "manager-a"))

    def test_history_is_tenant_bound_and_reviewer_only(self):
        lv = self.leave()
        self.mgr.post(f"{V1}/{lv.pk}/approve/")
        self.assertEqual(self.emp.get(f"{V1}/review/").status_code, 403)
        self.assertEqual(self.api(self.manager_b, self.org_b).get(f"{V1}/review/", {"status": "reviewed"}).data, [])

    def test_note_is_length_limited(self):
        lv = self.leave()
        r = self.mgr.post(f"{V1}/{lv.pk}/reject/", {"note": "x" * 1001}, format="json")
        self.assertEqual(r.status_code, 400)
