from datetime import datetime
import json

from django.contrib.auth.models import User
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import Client, TestCase
from django.urls import reverse
from django.utils import timezone

from .models import Event


class EventModelTests(TestCase):
    def test_slug_is_created_on_save(self):
        event = Event.objects.create(
            name='City Market',
            start=timezone.make_aware(datetime(2026, 4, 10, 10, 0)),
            end=timezone.make_aware(datetime(2026, 4, 10, 14, 0)),
        )
        self.assertTrue(event.slug.startswith('city-market-2026-04-10'))


class CalendarViewTests(TestCase):
    def setUp(self):
        Event.objects.create(
            name='Riverfront Market',
            location='Riverfront Pavilion',
            start=timezone.make_aware(datetime(2026, 4, 10, 10, 0)),
            end=timezone.make_aware(datetime(2026, 4, 10, 16, 0)),
            is_published=True,
        )

    def test_home_page_renders(self):
        response = self.client.get(reverse('home'))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Show visitors exactly where your business will be on any day.')

    def test_staff_dashboard_requires_login(self):
        response = self.client.get(reverse('event_dashboard'))
        self.assertEqual(response.status_code, 302)
        self.assertIn(reverse('login'), response.url)

    def test_staff_dashboard_for_staff_user(self):
        staff = User.objects.create_user(username='staffer', password='pass12345', is_staff=True)
        client = Client()
        client.login(username='staffer', password='pass12345')
        response = client.get(reverse('event_dashboard'))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Manage your public event calendar securely')
        self.assertContains(response, 'Generate a copy-ready widget snippet')
        self.assertContains(response, 'Import a previous backup')

    def test_embed_page_can_hide_header(self):
        response = self.client.get(reverse('calendar_embed') + '?header=0')
        self.assertEqual(response.status_code, 200)
        self.assertNotContains(response, 'Open full page')


class EventDashboardMutationTests(TestCase):
    def setUp(self):
        self.staff = User.objects.create_user(username='staffer', password='pass12345', is_staff=True)
        self.event = Event.objects.create(
            name='Editable Market',
            location='Town Square',
            start=timezone.make_aware(datetime(2026, 4, 12, 9, 0)),
            end=timezone.make_aware(datetime(2026, 4, 12, 12, 0)),
            is_published=True,
        )

    def _backup_file(self, payload):
        return SimpleUploadedFile(
            'events-backup.json',
            json.dumps(payload).encode('utf-8'),
            content_type='application/json',
        )

    def test_staff_can_export_event_backup(self):
        self.client.login(username='staffer', password='pass12345')
        response = self.client.get(reverse('event_export'))
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response['Content-Type'], 'application/json')
        self.assertIn('attachment; filename="roadshow-calendar-events-', response['Content-Disposition'])
        payload = json.loads(response.content)
        self.assertEqual(payload['version'], 1)
        self.assertEqual(payload['event_count'], 1)
        self.assertEqual(payload['events'][0]['slug'], self.event.slug)
        self.assertEqual(payload['events'][0]['name'], self.event.name)

    def test_staff_can_preview_event_backup_restore(self):
        self.client.login(username='staffer', password='pass12345')
        payload = {
            'version': 1,
            'project': 'Roadshow Calendar',
            'exported_at': '2026-04-01T10:30:00+00:00',
            'event_count': 1,
            'events': [
                {
                    'name': 'Recovered Market',
                    'slug': 'recovered-market-2026-04-20',
                    'location': 'Harbor Plaza',
                    'start': '2026-04-20T10:00:00+00:00',
                    'end': '2026-04-20T14:00:00+00:00',
                    'event_url': 'https://example.com/recovered',
                    'summary': 'Recovered from backup',
                    'is_published': False,
                }
            ],
        }

        response = self.client.post(reverse('event_import_preview'), {'backup_file': self._backup_file(payload)})
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Ready to replace the current calendar')
        self.assertContains(response, 'Recovered Market')
        self.assertContains(response, 'Confirm restore and replace events')
        self.assertIn('event_backup_import_payload', self.client.session)

    def test_staff_can_restore_event_backup(self):
        self.client.login(username='staffer', password='pass12345')
        payload = {
            'version': 1,
            'project': 'Roadshow Calendar',
            'exported_at': '2026-04-01T10:30:00+00:00',
            'event_count': 1,
            'events': [
                {
                    'name': 'Recovered Market',
                    'slug': 'recovered-market-2026-04-20',
                    'location': 'Harbor Plaza',
                    'start': '2026-04-20T10:00:00+00:00',
                    'end': '2026-04-20T14:00:00+00:00',
                    'event_url': 'https://example.com/recovered',
                    'summary': 'Recovered from backup',
                    'is_published': False,
                }
            ],
        }

        preview_response = self.client.post(reverse('event_import_preview'), {'backup_file': self._backup_file(payload)})
        self.assertEqual(preview_response.status_code, 200)

        response = self.client.post(reverse('event_import_restore'))
        self.assertRedirects(response, reverse('event_dashboard'))
        self.assertEqual(Event.objects.count(), 1)

        restored_event = Event.objects.get()
        self.assertEqual(restored_event.name, 'Recovered Market')
        self.assertEqual(restored_event.slug, 'recovered-market-2026-04-20')
        self.assertEqual(restored_event.location, 'Harbor Plaza')
        self.assertFalse(restored_event.is_published)
        self.assertFalse(Event.objects.filter(pk=self.event.pk).exists())
        self.assertNotIn('event_backup_import_payload', self.client.session)

    def test_staff_can_open_edit_page(self):
        self.client.login(username='staffer', password='pass12345')
        response = self.client.get(reverse('event_edit', args=[self.event.slug]))
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, 'Save changes')

    def test_staff_can_update_event(self):
        self.client.login(username='staffer', password='pass12345')
        response = self.client.post(
            reverse('event_edit', args=[self.event.slug]),
            {
                'name': 'Updated Market',
                'location': 'Town Square',
                'start': '2026-04-12T09:00',
                'end': '2026-04-12T13:00',
                'event_url': 'https://example.com/event',
                'summary': 'Updated details',
                'is_published': 'on',
            },
        )
        self.assertRedirects(response, reverse('event_dashboard_detail', args=[self.event.slug]))
        self.event.refresh_from_db()
        self.assertEqual(self.event.name, 'Updated Market')
        self.assertEqual(self.event.summary, 'Updated details')

    def test_staff_can_delete_event(self):
        self.client.login(username='staffer', password='pass12345')
        response = self.client.post(reverse('event_delete', args=[self.event.slug]))
        self.assertRedirects(response, reverse('event_dashboard'))
        self.assertFalse(Event.objects.filter(pk=self.event.pk).exists())
