import pytest
from django.contrib.auth import get_user_model
from model_bakery import baker
from appointment.models import Appointments
from django.utils import timezone
from unittest.mock import patch
from datetime import datetime

Users = get_user_model()


@pytest.mark.django_db()
class TestAppointmentModel:
    def test_return_str_model(self):
        appointment = baker.make(Appointments)
        assert (
            str(appointment)
            == f"Appointment by {appointment.email} on {appointment.scheduled_date_time.strftime('%B %d, %Y')}"
        )


@pytest.mark.django_db()
class TestAppointmentsFetch:
    def setup_method(self):
        self.admin = baker.make(Users, is_staff=True)
        self.user = baker.make(Users, is_staff=False)

        self.app_1 = baker.make(Appointments, remarks="unattended")
        self.app_2 = baker.make(Appointments)

    def test_fetch_appointments_by_non_admin_return_403(self, authenticate_user):
        api_client = authenticate_user(user=self.user)

        response = api_client.get("/api/appointment/appoint/")

        assert response.status_code == 403

    def test_fetch_appointments_by_admin_return_200(self, authenticate_user):
        api_client = authenticate_user(user=self.admin)

        response = api_client.get("/api/appointment/appoint/")

        assert response.status_code == 200
        assert response.data["count"] == 2


@pytest.mark.django_db()
class TestAppointmentsCreate:
    def setup_method(self):
        self.admin = baker.make(Users, is_staff=True)
        self.user = baker.make(Users, is_staff=False)

    @patch("appointment.views.send_emails.delay")
    def test_create_an_appointment_return_201(
        self, mock_send_emails, authenticate_user
    ):
        api_client = authenticate_user()

        scheduled_date_time = timezone.make_aware(datetime(2025, 3, 3, 10, 45))
        data = {
            "first_name": "John",
            "last_name": "Doe",
            "email": "johndoe@gmail.com",
            "contact_number": "0912345678",
            "company_name": "ABC Company",
            "branch": "QC",
            "scheduled_date_time": scheduled_date_time,
        }

        response = api_client.post("/api/appointment/appoint/", data=data)

        assert response.status_code == 201
        assert response.data["message"] == "Appointment was scheduled successfully."
        mock_send_emails.assert_called_once()

    @patch("appointment.views.send_emails.delay")
    def test_create_an_appointment_with_datetime_iso8601_z_format_return_201(
        self, mock_send_emails, authenticate_user
    ):
        api_client = authenticate_user()

        init_scheduled_date_time = timezone.make_aware(datetime(2025, 4, 3, 11, 00))
        scheduled_date_time = init_scheduled_date_time.strftime("%Y-%m-%dT%H:%M:%S.%fZ")

        data = {
            "first_name": "John",
            "last_name": "Doe",
            "email": "johndoe@gmail.com",
            "contact_number": "0912345678",
            "company_name": "ABC Company",
            "branch": "QC",
            "scheduled_date_time": scheduled_date_time,
        }

        response = api_client.post("/api/appointment/appoint/", data=data)

        assert response.status_code == 201
        assert response.data["message"] == "Appointment was scheduled successfully."
        mock_send_emails.assert_called_once()

    def test_create_an_appointment_with_QC_branch_and_during_saturday_return_400(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        scheduled_date_time = timezone.make_aware(datetime(2025, 3, 1, 10, 45))
        data = {
            "first_name": "John",
            "last_name": "Doe",
            "email": "johndoe@gmail.com",
            "contact_number": "0912345678",
            "company_name": "ABC Company",
            "branch": "QC",
            "scheduled_date_time": scheduled_date_time,
        }

        response = api_client.post("/api/appointment/appoint/", data=data)

        assert response.status_code == 400
        assert (
            response.data["message"]
            == "Appointment in QC branch is only available from Monday to Friday, 10:00 AM to 4:00 PM."
        )

    def test_create_an_appointment_with_scheduled_time_before_10am_return_400(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        scheduled_date_time = timezone.make_aware(datetime(2025, 3, 3, 9, 45))
        data = {
            "first_name": "John",
            "last_name": "Doe",
            "email": "johndoe@gmail.com",
            "contact_number": "0912345678",
            "company_name": "ABC Company",
            "branch": "QC",
            "scheduled_date_time": scheduled_date_time,
        }

        response = api_client.post("/api/appointment/appoint/", data=data)

        assert response.status_code == 400
        assert response.data["message"] == "Can only appoint from 10:00 AM to 4:00 PM."

    def test_create_an_appointment_with_scheduled_time_after_4pm_return_400(
        self, authenticate_user
    ):
        api_client = authenticate_user()

        scheduled_date_time = timezone.make_aware(datetime(2025, 3, 3, 16, 45))
        data = {
            "first_name": "John",
            "last_name": "Doe",
            "email": "johndoe@gmail.com",
            "contact_number": "0912345678",
            "company_name": "ABC Company",
            "branch": "QC",
            "scheduled_date_time": scheduled_date_time,
        }

        response = api_client.post("/api/appointment/appoint/", data=data)

        assert response.status_code == 400
        assert response.data["message"] == "Can only appoint from 10:00 AM to 4:00 PM."

@pytest.mark.django_db()
class TestAppointmentsUpdateRemarks:
    def setup_method(self):
        self.admin = baker.make(Users, is_staff=True)
        self.user = baker.make(Users, is_staff=False)

        self.appointment_1 = baker.make(Appointments)

    def test_update_remarks_by_non_admin_return_403(self, authenticate_user):
        api_client = authenticate_user(user=self.user)

        data = {"remarks": "attended"}
        response = api_client.patch(
            f"/api/appointment/appoint/{self.appointment_1.id}/", data=data
        )

        assert response.status_code == 403

    def test_update_remarks_by_admin_return_200(self, authenticate_user):
        api_client = authenticate_user(user=self.admin)

        data = {"remarks": "attended"}
        response = api_client.patch(
            f"/api/appointment/appoint/{self.appointment_1.id}/", data=data
        )

        assert response.status_code == 200
        assert "id" in response.data
        assert response.data["remarks"] == "Attended"