import json

from django.db import models
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.core.validators import URLValidator

from modelcluster.fields import ParentalKey
from wagtail.wagtailadmin.edit_handlers import (
    FieldPanel,
    InlinePanel,
    MultiFieldPanel,
    PageChooserPanel,
    StreamFieldPanel,
)

from wagtail.wagtailcore.fields import StreamField
from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
from wagtail.wagtailsearch import index

from opentech.apply.categories.models import Option
from opentech.public.utils.blocks import StoryBlock
from opentech.public.utils.models import (
    BaseFunding,
    BasePage,
    FundingMixin,
    RelatedPage,
)

from .widgets import CategoriesWidget


class ProjectContactDetails(models.Model):
    project_page = ParentalKey(
        'ProjectPage',
        related_name='contact_details'
    )
    site_titles = (
        ('website', "Main Website URL"),
        ('twitter', "Twitter Handle"),
        ('github', "Github Organisation or Project"),
    )
    site_urls = (
        ('website', ''),
        ('twitter', 'https://twitter.com/'),
        ('github', 'https://github.com/'),
    )
    service = models.CharField(
        max_length=200,
        choices=site_titles,
    )
    value = models.CharField(max_length=255)

    @property
    def url(self):
        return dict(self.site_urls)[self.service] + self.value

    def service_name(self):
        site_display = {
            'twitter': '@' + self.value,
            'github': 'Github',
            'website': 'Main Website',
        }
        return site_display[self.service]

    def clean(self):
        if self.service == 'twitter' and self.value.startswith('@'):
            self.username = self.username[1:]

        if self.service == 'website':
            validate = URLValidator()
            try:
                validate(self.value)
            except ValidationError as e:
                raise ValidationError({'value': e})


class ProjectPageRelatedPage(RelatedPage):
    source_page = ParentalKey('ProjectPage', related_name='related_pages')

    panels = [
        PageChooserPanel('page', 'projects.ProjectPage'),
    ]


class ProjectFunding(BaseFunding):
    page = ParentalKey('ProjectPage', related_name='funding')


class ProjectPage(FundingMixin, BasePage):
    STATUSES = (
        ('idea', "Just an Idea. (Pre-alpha)"),
        ('exists', "It Exists! (Alpha/Beta)"),
        ('release', "It's basically done. (Release)"),
        ('production', "People Use it. (Production)"),
    )

    subpage_types = []
    parent_page_types = ['ProjectIndexPage']

    introduction = models.TextField(blank=True)
    icon = models.ForeignKey(
        'images.CustomImage',
        null=True,
        blank=True,
        related_name='+',
        on_delete=models.SET_NULL
    )
    status = models.CharField(choices=STATUSES, max_length=25, default=STATUSES[0][0])
    body = StreamField(StoryBlock())

    categories = models.TextField(default='{}', blank=True)

    search_fields = BasePage.search_fields + [
        index.SearchField('introduction'),
        index.SearchField('body'),
    ]

    content_panels = BasePage.content_panels + [
        ImageChooserPanel('icon'),
        FieldPanel('introduction'),
        FieldPanel('status'),
        StreamFieldPanel('body'),
        InlinePanel('contact_details', label="Contact Details"),
        InlinePanel('related_pages', label="Related Projects"),
    ] + FundingMixin.content_panels + [
        MultiFieldPanel(
            [FieldPanel('categories', widget=CategoriesWidget)],
            heading="Categories",
            classname="collapsible collapsed",
        ),
    ]

    def category_options(self):
        categories = json.loads(self.categories)
        options = [int(id) for options in categories.values() for id in options]
        return Option.objects.select_related().filter(id__in=options).order_by('category')


class ProjectIndexPage(BasePage):
    subpage_types = ['ProjectPage']
    parent_page_types = ['home.Homepage']

    introduction = models.TextField(blank=True)

    content_panels = BasePage.content_panels + [
        FieldPanel('introduction'),
    ]

    search_fields = BasePage.search_fields + [
        index.SearchField('introduction'),
    ]

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        subpages = self.get_children().live()
        per_page = settings.DEFAULT_PER_PAGE
        page_number = request.GET.get('page')
        paginator = Paginator(subpages, per_page)

        try:
            subpages = paginator.page(page_number)
        except PageNotAnInteger:
            subpages = paginator.page(1)
        except EmptyPage:
            subpages = paginator.page(paginator.num_pages)

        context['subpages'] = subpages

        return context