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 RegistrationDomainRule, RegistrationRestrictionSetting, EmailVerificationToken, SMTPSetting
from apps.events.models import Event, TaskArea, Shift, ShiftSignup

User = get_user_model()

class UserRegistrationTests(TestCase):
    def setUp(self):
        self.client = APIClient()

    def test_domain_restriction_enforcement(self):
        # Enable domain restriction
        setting = RegistrationRestrictionSetting.get_solo()
        setting.is_restriction_enabled = True
        setting.save()

        # Add rule for verein.de
        RegistrationDomainRule.objects.create(domain='verein.de', is_active=True)

        # Attempt registration with non-allowed domain
        res = self.client.post('/api/users/register/', {
            'username': 'testuser',
            'email': 'user@otherdomain.com',
            'password': 'password123',
            'display_name': 'Test User'
        })
        self.assertEqual(res.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertIn('Registrierungen sind derzeit nur für folgende E-Mail-Domains erlaubt', str(res.data))

        # Attempt registration with allowed domain
        res_ok = self.client.post('/api/users/register/', {
            'username': 'alloweduser',
            'email': 'user@verein.de',
            'password': 'password123',
            'display_name': 'Allowed User'
        })
        self.assertEqual(res_ok.status_code, status.HTTP_201_CREATED)
        self.assertTrue(res_ok.data.get('requires_verification'))

    def test_email_verification_flow(self):
        # Register new user
        res_reg = self.client.post('/api/users/register/', {
            'username': 'verify_user',
            'email': 'verify@example.com',
            'password': 'password123',
            'display_name': 'Verify User'
        })
        self.assertEqual(res_reg.status_code, status.HTTP_201_CREATED)
        self.assertTrue(res_reg.data.get('requires_verification'))
        v_token_str = res_reg.data.get('verification_token')

        # Login should be blocked prior to verification or admin approval
        res_login_blocked = self.client.post('/api/users/login/', {
            'username': 'verify_user',
            'password': 'password123'
        })
        self.assertEqual(res_login_blocked.status_code, status.HTTP_403_FORBIDDEN)

        # Verify email using verification token
        res_verify = self.client.post('/api/users/verify-email/', {
            'token': v_token_str
        })
        self.assertEqual(res_verify.status_code, status.HTTP_200_OK)
        self.assertIn('token', res_verify.data)

        # Login should now succeed
        res_login_ok = self.client.post('/api/users/login/', {
            'username': 'verify_user',
            'password': 'password123'
        })
        self.assertEqual(res_login_ok.status_code, status.HTTP_200_OK)
        self.assertIn('token', res_login_ok.data)

    def test_email_verification_opt_out(self):
        # Set require_email_verification to False (Opt-Out)
        setting = RegistrationRestrictionSetting.get_solo()
        setting.require_email_verification = False
        setting.save()

        # Register user with Opt-Out
        res_reg = self.client.post('/api/users/register/', {
            'username': 'optout_user',
            'email': 'optout@example.com',
            'password': 'password123',
            'display_name': 'Opt-Out User'
        })
        self.assertEqual(res_reg.status_code, status.HTTP_201_CREATED)
        self.assertIn('token', res_reg.data)
        self.assertFalse(res_reg.data.get('requires_verification'))

        # Immediate login works
        res_login = self.client.post('/api/users/login/', {
            'username': 'optout_user',
            'password': 'password123'
        })
        self.assertEqual(res_login.status_code, status.HTTP_200_OK)

    def test_guest_shift_claiming_on_registration(self):
        # Create event, task area, shift
        event = Event.objects.create(title="Test Event", start_date="2026-08-01", end_date="2026-08-02")
        ta = TaskArea.objects.create(event=event, name="Tresendienst")
        shift = Shift.objects.create(task_area=ta, title="Frühschicht", start_time="09:00", end_time="13:00")

        # Guest signs up with guest_name="Max Mustermann"
        session = self.client.session
        session.save()
        session_key = session.session_key

        signup = ShiftSignup.objects.create(
            shift=shift,
            guest_name="Max Mustermann",
            guest_session_key=session_key
        )

        # Now register user with display_name="Max Mustermann"
        res = self.client.post('/api/users/register/', {
            'username': 'max_mustermann',
            'email': 'max@example.com',
            'password': 'password123',
            'display_name': 'Max Mustermann'
        })
        self.assertEqual(res.status_code, status.HTTP_201_CREATED)
        self.assertEqual(res.data['claimed_shifts_count'], 1)

        signup.refresh_from_db()
        self.assertIsNotNone(signup.user)
        self.assertEqual(signup.user.username, 'max_mustermann')
        self.assertIsNone(signup.guest_name)

    def test_admin_approval_workflow(self):
        # Register user
        res_reg = self.client.post('/api/users/register/', {
            'username': 'pending_user',
            'email': 'pending@example.com',
            'password': 'password123',
            'display_name': 'Pending User'
        })
        self.assertEqual(res_reg.status_code, status.HTTP_201_CREATED)

        # Attempt login before approval (should be blocked)
        res_login_fail = self.client.post('/api/users/login/', {
            'username': 'pending_user',
            'password': 'password123'
        })
        self.assertEqual(res_login_fail.status_code, status.HTTP_403_FORBIDDEN)

        # Admin approves user
        admin = User.objects.create_superuser(username='admin', email='admin@test.com', password='adminpassword')
        self.client.force_authenticate(user=admin)

        pending_user = User.objects.get(username='pending_user')
        res_approve = self.client.post(f'/api/users/{pending_user.id}/approve/')
        self.assertEqual(res_approve.status_code, status.HTTP_200_OK)

        # Attempt login after approval (should succeed)
        self.client.logout()
        res_login_ok = self.client.post('/api/users/login/', {
            'username': 'pending_user',
            'password': 'password123'
        })
        self.assertEqual(res_login_ok.status_code, status.HTTP_200_OK)
        self.assertIn('token', res_login_ok.data)

    def test_guest_claim_token_and_registration_link(self):
        admin = User.objects.create_user(username="admin_gen", email="admin_gen@test.com", password="password123", is_admin_user=True)
        event = Event.objects.create(title="Claim Event", start_date="2026-09-01", end_date="2026-09-02")
        ta = TaskArea.objects.create(event=event, name="Kasse")
        shift = Shift.objects.create(task_area=ta, title="Spätschicht", start_time="18:00", end_time="22:00")
        signup = ShiftSignup.objects.create(shift=shift, guest_name="Erika Muster")

        # Admin generates claim link
        self.client.force_authenticate(user=admin)
        res_token = self.client.post(f'/api/users/signups/{signup.id}/generate-claim-link/')
        self.assertEqual(res_token.status_code, status.HTTP_200_OK)
        claim_token = res_token.data['token']
        self.assertEqual(res_token.data['guest_name'], 'Erika Muster')

        # Recipient registers using claim_token
        self.client.logout()
        res_reg = self.client.post('/api/users/register/', {
            'username': 'erika_muster',
            'email': 'erika@muster.de',
            'password': 'password123',
            'display_name': 'Erika Muster',
            'claim_token': claim_token
        })
        self.assertEqual(res_reg.status_code, status.HTTP_201_CREATED)

        signup.refresh_from_db()
        self.assertIsNotNone(signup.user)
        self.assertEqual(signup.user.username, 'erika_muster')
        self.assertIsNone(signup.guest_name)

    def test_smtp_settings_configuration(self):
        admin = User.objects.create_superuser(username='smtp_admin', email='smtp@test.com', password='password123')
        self.client.force_authenticate(user=admin)

        # GET SMTP setting
        res_get = self.client.get('/api/users/smtp-setting/')
        self.assertEqual(res_get.status_code, status.HTTP_200_OK)
        self.assertFalse(res_get.data['is_active'])

        # UPDATE SMTP setting
        res_post = self.client.post('/api/users/smtp-setting/', {
            'is_active': True,
            'host': 'smtp.mailtrap.io',
            'port': 2525,
            'username': 'test_user',
            'password': 'test_password',
            'from_email': 'noreply@test.de'
        }, format='json')
        self.assertEqual(res_post.status_code, status.HTTP_200_OK)
        self.assertTrue(res_post.data['is_active'])
        self.assertEqual(res_post.data['host'], 'smtp.mailtrap.io')
