import uuid
from datetime import timedelta

from django.conf import settings
from django.test import TestCase
from django.urls import reverse
from django.utils.timezone import now

from core.models import Assembly, Conference, ConferenceMember, Event, PlatformUser, Room
from core.utils import GitRepo, mail2uuid, mask_url, resolve_internal_url, scheme_and_netloc_from_url, str2timedelta


class UtilsTests(TestCase):
    def test_maskurl(self):
        checks = [
            ('http://foo.tld/', 'http://foo.tld/'),
            ('http://foo.tld/bar', 'http://foo.tld/bar'),
            ('http://foo.tld/bar?fnord', 'http://foo.tld/bar'),
            ('https://anon:secret@foo.tld/bar?fnord', 'https://foo.tld/bar'),
            ('https://anon@foo.tld/bar/', 'https://foo.tld/bar/'),
        ]

        for check in checks:
            self.assertEqual(check[1], mask_url(check[0]), check[0])

    def test_str2timedelta(self):
        checks = [
            ('0:30:00', timedelta(minutes=30)),
            ('15m', timedelta(minutes=15)),
            ('1h 15m', timedelta(hours=1, minutes=15)),
            ('5s', timedelta(seconds=5)),
        ]

        for check in checks:
            self.assertEqual(check[1], str2timedelta(check[0]), check[0])

    def test_link_parsing(self):
        checks = [
            ('https://example.com/foo?bar=baz', 'https://example.com'),
            ('https://one.more.example.com/foo?bar=baz', 'https://one.more.example.com'),
            ('http://localhost:8000/backoffice/', 'http://localhost:8000'),
            ('events.ccc.de', None),  # just a path, not an URL
            ('//events.ccc.de', 'https://events.ccc.de'),
        ]

        for check in checks:
            self.assertEqual(check[1], scheme_and_netloc_from_url(check[0]))

    def test_mail2uuid(self):
        expected_uuid = uuid.UUID('c25334d0-9539-55e3-92b4-f559c384522b')
        self.assertEqual(expected_uuid, mail2uuid('hub@cccv.de'))


class InternalUrlTests(TestCase):
    def setUp(self):
        self.conference1 = Conference(slug='foo', name='Foo Conference', start=now() - timedelta(days=1), end=now() + timedelta(days=1))
        self.conference1.save()

        self.user = PlatformUser(username='bernd')
        self.user.save()
        ConferenceMember(conference=self.conference1, user=self.user).save()

        self.assembly1a = Assembly(conference=self.conference1, slug='fnord', name='Fnord Assembly', is_official=True)
        self.assembly1a.save()

        self.room1a = Room(conference=self.conference1, assembly=self.assembly1a, name='Saal 1', room_type=Room.RoomType.LECTURE_HALL)
        self.room1a.save()

        self.valid_event = {
            'conference': self.conference1,
            'assembly': self.assembly1a,
            'name': 'testEvent',
            'slug': 'testEvent',
            'kind': Event.Kind.ASSEMBLY,
            'room': self.room1a,
            'schedule_start': now(),
            'schedule_duration': timedelta(hours=1),
            'is_public': True,
        }

    def test_resolve_internal_url(self):
        base_url = settings.PLAINUI_BASE_URL
        checks = [
            ('https://example.com/foo?bar=baz', 'https://example.com/foo?bar=baz'),
            ('conference://assemblies', base_url + reverse('plainui:assemblies')),
            ('conference://assemblies?foo=bar', base_url + reverse('plainui:assemblies') + '?foo=bar'),
            ('assembly://fnord', base_url + reverse('plainui:assembly', kwargs={'assembly_slug': 'fnord'})),
        ]

        for check in checks:
            self.assertEqual(check[1], resolve_internal_url(check[0]))


class GitRepoOfflineTests(TestCase):
    def test_invalid_url_local_path(self):
        with self.assertRaisesMessage(ValueError, 'Invalid protocol file'):
            GitRepo('file://test')

    def test_invalid_url_environment_variable(self):
        with self.assertRaisesMessage(ValueError, "Env variables not allowed in GitRepo's repo_url."):
            GitRepo('https://$test')

    def test_valid_url(self):
        repo = GitRepo('https://git.cccv.de/hub/wiki-import-test.git?branch=test&path=other#develop')
        self.assertEqual(repo.repo_url, 'https://git.cccv.de/hub/wiki-import-test.git')
        self.assertEqual(repo.repo_branch, 'test')
        self.assertEqual(repo.repo_path, 'other')
        self.assertEqual(repo.repo_hash, 'develop')

    def test_url_params(self):
        repo_test_baseurl = 'https://git.cccv.de/hub/wiki-import-test.git'

        repo = GitRepo(f'https://{repo_test_baseurl}')
        self.assertEqual(f'https://{repo_test_baseurl}', repo.repo_url)
        self.assertIsNone(repo.repo_branch)
        self.assertIsNone(repo.repo_path)
        self.assertIsNone(repo.repo_hash)


class GitRepoRemoteTests(TestCase):
    def test_clone(self):
        with GitRepo('https://git.cccv.de/hub/wiki-import-test.git') as repo:
            documents = repo.get_documents()
            self.assertEqual(len(documents), 1)

    def test_clone_branch(self):
        with GitRepo('https://git.cccv.de/hub/wiki-import-test.git?branch=two-files') as repo:
            documents = repo.get_documents()
            self.assertEqual(len(documents), 2)

    def test_clone_reference(self):
        with GitRepo('https://git.cccv.de/hub/wiki-import-test.git?branch=other#92319c970c0ff90bcc0a3d14a01e795f3e4dcb99') as repo:
            documents = repo.get_documents()
            self.assertEqual(len(documents), 3)