import pytest
from django.contrib.auth import get_user_model
from rest_framework.test import APIClient
from apps.tasks.models import Task, Message, Approval


@pytest.fixture
def user(db):
    User = get_user_model()
    return User.objects.create_user(email="task@example.com", password="pass123")


@pytest.fixture
def api_user(user):
    """User with the tasks RBAC permission (endpoints are HasMenuPermission-gated)."""
    from apps.core.models import Permission, Role, UserRole
    role = Role.objects.create(name="Task Tester", slug="task-tester")
    perm, _ = Permission.objects.get_or_create(
        domain="tasks", action="*", defaults={"label": "All tasks"})
    role.permissions.add(perm)
    UserRole.objects.create(user=user, role=role)
    return user


@pytest.fixture
def task(user):
    return Task.objects.create(
        title="Fix bug",
        description="Fix login bug",
        created_by=user
    )


@pytest.mark.django_db
class TestTaskModel:
    def test_create_task(self, user):
        t = Task.objects.create(
            title="New Task",
            description="Task description",
            created_by=user
        )
        assert t.title == "New Task"
        assert t.status == "todo"
        assert t.priority == "medium"

    def test_task_statuses(self, user):
        for status in ["todo", "in_progress", "review", "done", "cancelled"]:
            t = Task.objects.create(title=f"Task {status}", created_by=user, status=status)
            assert t.status == status


@pytest.mark.django_db
class TestMessageModel:
    def test_create_message(self, user):
        msg = Message.objects.create(
            sender=user,
            content="Hello there"
        )
        assert msg.content == "Hello there"
        assert msg.is_read is False


@pytest.mark.django_db
class TestApprovalModel:
    def test_create_approval(self, user):
        approver = user
        approval = Approval.objects.create(
            title="Leave Request",
            description="Please approve",
            requester=user,
            approver=approver
        )
        assert approval.status == "pending"


@pytest.mark.django_db
class TestTaskAPI:
    def test_post_task_sets_created_by(self, api_user):
        user = api_user
        client = APIClient()
        client.force_authenticate(user=user)
        res = client.post("/api/tasks/", {"title": "API task"}, format="json")
        assert res.status_code == 201, res.content
        assert res.data["title"] == "API task"
        assert res.data["status"] == "todo"
        assert res.data["priority"] == "medium"
        task = Task.objects.get(pk=res.data["id"])
        assert task.created_by_id == user.id

    def test_post_task_with_optional_fields(self, api_user):
        client = APIClient()
        client.force_authenticate(user=api_user)
        res = client.post(
            "/api/tasks/",
            {"title": "Detailed", "description": "desc", "priority": "high", "status": "in_progress"},
            format="json",
        )
        assert res.status_code == 201, res.content
        assert res.data["priority"] == "high"
        assert res.data["status"] == "in_progress"

    def test_post_task_requires_title(self, api_user):
        client = APIClient()
        client.force_authenticate(user=api_user)
        res = client.post("/api/tasks/", {}, format="json")
        assert res.status_code == 400


@pytest.mark.django_db
class TestApprovalAPI:
    def test_post_approval_sets_requester(self, api_user):
        user = api_user
        User = get_user_model()
        approver = User.objects.create_user(email="approver@example.com", password="pass123")
        client = APIClient()
        client.force_authenticate(user=user)
        res = client.post(
            "/api/approvals/",
            {"title": "Need approval", "description": "why", "approver": str(approver.id)},
            format="json",
        )
        assert res.status_code == 201, res.content
        assert str(res.data["requester"]) == str(user.id)
        assert str(res.data["approver"]) == str(approver.id)
        assert res.data["status"] == "pending"

    def test_post_approval_requires_approver(self, api_user):
        client = APIClient()
        client.force_authenticate(user=api_user)
        res = client.post(
            "/api/approvals/",
            {"title": "Need approval", "description": "why"},
            format="json",
        )
        assert res.status_code == 400