from django.test import TestCase
from django.contrib.auth import get_user_model
from rest_framework.test import APIClient
from rest_framework import status
from .models import Skill, Event, TaskArea, Shift, ShiftSignup

User = get_user_model()

class EventAndShiftTests(TestCase):
    def setUp(self):
        self.client = APIClient()
        self.skill = Skill.objects.create(name="Ersthelfer", color="#ef4444")
        self.user = User.objects.create_user(
            username="doctor_who", email="doctor@tardis.org", password="password123", display_name="Dr. Who"
        )
        self.event = Event.objects.create(title="Sommerfest", start_date="2026-08-10", end_date="2026-08-12")
        self.ta = TaskArea.objects.create(event=self.event, name="Sanitätsdienst")
        self.shift = Shift.objects.create(
            task_area=self.ta, title="Hauptschicht", start_time="10:00", end_time="18:00", max_participants=2
        )
        self.shift.required_skills.add(self.skill)

    def test_guest_cannot_signup_for_skill_required_shift(self):
        res = self.client.post(f'/api/shifts/{self.shift.id}/signup/', {
            'guest_name': 'Guest User',
            'captcha_token': 'test-captcha-token'
        })
        self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('Gäste können keine Fähigkeiten haben', res.data['error'])

    def test_user_without_skill_blocked_and_with_skill_allowed(self):
        self.client.force_authenticate(user=self.user)

        # Attempt signup without skill
        res_fail = self.client.post(f'/api/shifts/{self.shift.id}/signup/')
        self.assertEqual(res_fail.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('Dir fehlen folgende erforderliche Fähigkeiten', res_fail.data['error'])

        # Add skill to user
        self.user.skills.add(self.skill)

        # Attempt signup with skill
        res_ok = self.client.post(f'/api/shifts/{self.shift.id}/signup/')
        self.assertEqual(res_ok.status_code, status.HTTP_201_CREATED)

    def test_guest_privacy_redaction_in_matrix(self):
        # Add signup
        self.user.skills.add(self.skill)
        ShiftSignup.objects.create(shift=self.shift, user=self.user)

        # Unauthenticated request (Guest)
        anon_client = APIClient()
        res_anon = anon_client.get(f'/api/events/{self.event.id}/matrix/')
        self.assertEqual(res_anon.status_code, status.HTTP_200_OK)
        signup_data_anon = res_anon.data['task_areas'][0]['shifts'][0]['signups'][0]
        self.assertEqual(signup_data_anon['display_name'], 'Belegt (Anonym)')

        # Authenticated request
        self.client.force_authenticate(user=self.user)
        res_auth = self.client.get(f'/api/events/{self.event.id}/matrix/')
        self.assertEqual(res_auth.status_code, status.HTTP_200_OK)
        signup_data_auth = res_auth.data['task_areas'][0]['shifts'][0]['signups'][0]
        self.assertEqual(signup_data_auth['display_name'], 'Dr. Who')

    def test_event_edit_and_deactivation_permissions(self):
        admin = User.objects.create_user(
            username="admin_user", email="admin@verein.de", password="password123", is_admin_user=True
        )
        other_user = User.objects.create_user(
            username="other_user", email="other@verein.de", password="password123"
        )
        user_event = Event.objects.create(
            title="User Event", start_date="2026-09-01", end_date="2026-09-02", created_by=self.user
        )

        # Other user cannot deactivate user_event
        self.client.force_authenticate(user=other_user)
        res_fail = self.client.patch(f'/api/events/{user_event.id}/', {'is_active': False})
        self.assertEqual(res_fail.status_code, status.HTTP_403_FORBIDDEN)

        # Creator (self.user) CAN deactivate their own event
        self.client.force_authenticate(user=self.user)
        res_creator_ok = self.client.patch(f'/api/events/{user_event.id}/', {'is_active': False})
        self.assertEqual(res_creator_ok.status_code, status.HTTP_200_OK)
        self.assertFalse(res_creator_ok.data['is_active'])

        # Admin CAN manage and reactivate any event
        self.client.force_authenticate(user=admin)
        res_admin_ok = self.client.patch(f'/api/events/{user_event.id}/', {'is_active': True})
        self.assertEqual(res_admin_ok.status_code, status.HTTP_200_OK)
        self.assertTrue(res_admin_ok.data['is_active'])

    def test_shift_and_participant_management_permissions(self):
        creator = User.objects.create_user(username="creator", email="creator@verein.de", password="password123")
        other_user = User.objects.create_user(username="other", email="other@verein.de", password="password123")

        event = Event.objects.create(title="Creator Event", start_date="2026-09-01", end_date="2026-09-02", created_by=creator)
        ta = TaskArea.objects.create(event=event, name="Bar")
        shift = Shift.objects.create(task_area=ta, title="Abendschicht", start_time="19:00", end_time="23:00", max_participants=2)

        signup = ShiftSignup.objects.create(shift=shift, user=other_user)

        # Other user CANNOT remove creator's participant from creator's shift
        third_user = User.objects.create_user(username="third", email="third@verein.de", password="password123")
        self.client.force_authenticate(user=third_user)
        res_fail = self.client.delete(f'/api/shifts/{shift.id}/signup/', {'signup_id': signup.id}, format='json')
        self.assertEqual(res_fail.status_code, status.HTTP_404_NOT_FOUND)

        # Creator CAN remove participant from shift on their own event
        self.client.force_authenticate(user=creator)
        res_ok = self.client.delete(f'/api/shifts/{shift.id}/signup/', {'signup_id': signup.id}, format='json')
        self.assertEqual(res_ok.status_code, status.HTTP_200_OK)
        self.assertFalse(ShiftSignup.objects.filter(pk=signup.id).exists())

    def test_co_manager_permissions_and_guest_skill_bypass(self):
        owner = User.objects.create_user(username="owner_user", email="owner@test.de", password="password123")
        co_manager = User.objects.create_user(username="comanager", email="comanager@test.de", password="password123")
        
        event = Event.objects.create(title="CoManaged Event", start_date="2026-10-01", end_date="2026-10-02", created_by=owner)
        event.co_managers.add(co_manager)
        
        ta = TaskArea.objects.create(event=event, name="Einlass")
        shift = Shift.objects.create(task_area=ta, title="Spätschicht", start_time="20:00", end_time="24:00", max_participants=5)
        shift.required_skills.add(self.skill)

        # Co-manager can edit event
        self.client.force_authenticate(user=co_manager)
        res_edit = self.client.patch(f'/api/events/{event.id}/', {'location': 'Haupteingang'})
        self.assertEqual(res_edit.status_code, status.HTTP_200_OK)
        self.assertEqual(res_edit.data['location'], 'Haupteingang')

        # Co-manager CAN register a guest on skill-required shift (skill check bypassed for manager!)
        res_guest = self.client.post(f'/api/shifts/{shift.id}/signup/', {'guest_name': 'VIP Gast'}, format='json')
        self.assertEqual(res_guest.status_code, status.HTTP_201_CREATED)
        self.assertIn('ohne Qualifikationsprüfung', res_guest.data['message'])

        # Check signup exists
        signup_id = res_guest.data['signup_id']
        signup = ShiftSignup.objects.get(pk=signup_id)
        self.assertEqual(signup.guest_name, 'VIP Gast')

        # Co-manager can delete any signup
        res_del = self.client.delete(f'/api/shifts/{shift.id}/signup/', {'signup_id': signup_id}, format='json')
        self.assertEqual(res_del.status_code, status.HTTP_200_OK)
