__all__ = (
    'ComponentGalleryView',
    'IndexView',
    'LandingView',
    'MetaNavView',
    'SearchView',
    'TagView',
    'UnderConstructionView',
)

from datetime import timedelta

from django.contrib.contenttypes.models import ContentType
from django.shortcuts import get_object_or_404, redirect
from django.urls import reverse
from django.utils import timezone
from django.utils.timezone import now
from django.views.generic.base import TemplateView

from core.models import (
    Assembly,
    ConferenceTag,
    Event,
    MetaNavItem,
    Project,
    Room,
    RoomLink,
    TagItem,
)
from core.search import search

from plainui.forms import (
    ExampleForm,
)
from plainui.views.utils import (
    ConferenceRequiredMixin,
    session_get_favorite_assemblies,
    session_get_favorite_events,
    session_get_favorite_projects,
)


class LandingView(ConferenceRequiredMixin, TemplateView):
    template_name = 'plainui/landing.html.j2'
    require_login = False
    require_conference_member = False

    def get(self, request, *args, **kwargs):
        if not self.conf.require_login:
            return redirect(reverse('plainui:index'))
        return super().get(request, *args, **kwargs)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['conf'] = self.conf
        context['hide_header'] = True

        return context


class IndexView(ConferenceRequiredMixin, TemplateView):
    template_name = 'plainui/index.html.j2'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['conf'] = self.conf
        context['is_favorite_events'] = session_get_favorite_events(self.request.session, self.request.user)
        context['public_streams'] = (
            Room.objects.conference_accessible(self.conf)
            .filter(is_public_fahrplan=True, links__link_type=RoomLink.LinkType.MEDIA_CCC_DE)
            .order_by('official_room_order')
            .distinct()
        )

        context['upcoming_events_official'] = (
            Event.objects.conference_accessible(self.conf).order_by('schedule_start').filter(kind=Event.Kind.OFFICIAL).filter(schedule_end__gt=now())[:10]
        )
        context['upcoming_events_self_organized'] = (
            Event.objects.conference_accessible(self.conf).order_by('schedule_start').filter(kind=Event.Kind.SELF_ORGANIZED).filter(schedule_end__gt=now())[:10]
        )

        context['report_info'] = {'enabled': True}

        return context


class UnderConstructionView(ConferenceRequiredMixin, TemplateView):
    template_name = 'plainui/under_construction.html.j2'
    only_published = False

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['conf'] = self.conf

        context['report_info'] = {'enabled': True}

        return context


class MetaNavView(ConferenceRequiredMixin, TemplateView):
    require_login = False
    require_conference_member = False
    only_published = False
    template_name = 'plainui/metanav.html.j2'

    # TODO: implement caching, e.g. using ConferenceExportCache?

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['conf'] = self.conf
        context['include_header'] = self.request.GET.get('full') != '0'
        context['theme'] = 'dark'  # TODO: react to theme switching
        context['active_item'] = self.request.GET.get('active')
        context['items'] = MetaNavItem.objects.for_conference(self.conf)
        return context


class TagView(ConferenceRequiredMixin, TemplateView):
    template_name = 'plainui/tag.html.j2'

    def get_context_data(self, tag_slug, **kwargs):
        context = super().get_context_data(tag_slug=tag_slug, **kwargs)
        context['conf'] = self.conf

        tag = get_object_or_404(ConferenceTag, slug=tag_slug)
        context['tag'] = tag

        # TODO other types. What should we link here?
        # TODO: consider using views.utils.event_filter() here
        context['events'] = (
            Event.objects.conference_accessible(self.conf)
            .filter(id__in=TagItem.objects.filter(tag=tag, target_type=ContentType.objects.get_for_model(Event)).values_list('target_id'))
            .filter(schedule_start__isnull=False, schedule_end__isnull=False)
            .order_by('schedule_start', 'schedule_end')
        )
        context['my_favorite_events'] = session_get_favorite_events(self.request.session, self.request.user)

        context['assemblies'] = Assembly.objects.conference_accessible(self.conf).filter(
            id__in=TagItem.objects.filter(tag=tag, target_type=ContentType.objects.get_for_model(Assembly)).values_list('target_id')
        )
        context['my_favorite_assemblies'] = session_get_favorite_assemblies(self.request.session, self.request.user)
        context['projects'] = Project.objects.conference_accessible(self.conf).filter(tags__tag=tag)
        context['my_favorite_projects'] = session_get_favorite_projects(self.request.session, self.request.user)

        return context


class SearchView(ConferenceRequiredMixin, TemplateView):
    template_name = 'plainui/search.html.j2'

    def get(self, request, *args, **kwargs):
        return redirect(reverse('plainui:index'))

    def post(self, request, **kwargs):
        context = self.get_context_data(**kwargs)
        return self.render_to_response(context)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['conf'] = self.conf
        q = self.request.POST.get('q', '')
        context['search_query'] = q

        results = []
        for result in search(self.request.user, self.conf, q):
            results.append({'type': result.__class__.__name__, 'item': result})
        context['search_results'] = results
        return context


class ComponentGalleryView(TemplateView):
    template_name = 'plainui/component_gallery.html.j2'

    def get_context_data(self, **kwargs):
        form_invalid = ExampleForm({'text': '', 'textarea': ''})
        form_invalid.full_clean()
        return super().get_context_data(
            **kwargs,
            form_valid=ExampleForm({'text': 'lorem ipsum', 'password': 'lorem ipsum', 'checkbox': True, 'textarea': 'blork'}),
            form_invalid=form_invalid,
            conf={
                'slug': 'sample',
                'name': 'Example',
                'id': 'confID',
                'get_navigation_tree': lambda: [
                    {
                        'label': 'Conference',
                        'title': 'Conference',
                        'icon': 'hammer',
                        'url': '/',
                    }
                ],
                'map_config': {
                    'frontend': {
                        'start': {'latitude': 53.56172, 'longitude': 9.98593, 'zoom': 16},
                        'style': {
                            'version': 8,
                            'sources': {
                                'osm-raster': {
                                    'type': 'raster',
                                    'tiles': ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
                                    'tileSize': 256,
                                    'attribution': '© OpenStreetMap contributors / test use only!!!',
                                }
                            },
                            'layers': [{'id': 'simple-tiles', 'type': 'raster', 'source': 'osm-raster', 'minzoom': 0, 'maxzoom': 19}],
                        },
                    }
                },
            },
            demo_map_startpos={'longitude': 9.98641, 'latitude': 53.56148},
            csrf_input='xss-safe',
            hide_header=True,
            time1=timezone.now(),
            time2=timezone.now() + timedelta(minutes=45),
            duration=timedelta(minutes=45),
        )