import random

import factory
import wagtail_factories
from django.contrib.auth import get_user_model
from factory import CREATE_STRATEGY
from wagtail.core import blocks
from wagtail.core.models import Page, Site
from wagtail.core.rich_text import RichText

from assignments.models import Assignment
from basicknowledge.models import BasicKnowledge
from books.blocks import BasicKnowledgeBlock, ImageUrlBlock, LinkBlock, AssignmentBlock, VideoBlock
from books.models import Book, Topic, Module, Chapter, ContentBlock, TextBlock
from core.factories import BasePageFactory, fake, DummyImageFactory, fake_paragraph, fake_title


class BookFactory(BasePageFactory):
    class Meta:
        model = Book

    @staticmethod
    def create_default_structure():
        site = wagtail_factories.SiteFactory.create(is_default_site=True)
        Page.objects.get(title='Root').delete()

        book = BookFactory.create(parent=site.root_page, title='A book')
        topic = TopicFactory.create(parent=book, order=1, title='A topic')
        module = ModuleFactory.create(parent=topic,
                                      title="A module",
                                      meta_title="Modul 1",
                                      teaser="Whatever",
                                      intro="<p>Hello</p>")
        chapter = ChapterFactory.create(parent=module, title="A chapter")
        content_block = ContentBlockFactory.create(parent=chapter, module=module, title="A content block", type="task",
                                                   contents=[])

        return book, topic, module, chapter, content_block


class TopicFactory(BasePageFactory):
    class Meta:
        model = Topic

    order = 0
    teaser = factory.LazyAttribute(lambda x: fake.sentence(nb_words=random.randint(8, 12)))
    description = factory.LazyAttribute(lambda x: fake.text(max_nb_chars=200))


class ModuleFactory(BasePageFactory):
    class Meta:
        model = Module

    meta_title = factory.LazyAttribute(lambda x: fake.text(max_nb_chars=20))
    teaser = factory.LazyAttribute(lambda x: fake.sentence(nb_words=random.randint(8, 12)))
    intro = factory.LazyAttribute(lambda x: fake.text(max_nb_chars=200))

    hero_image = factory.SubFactory(DummyImageFactory)


class ChapterFactory(BasePageFactory):
    class Meta:
        model = Chapter


class TextBlockFactory(wagtail_factories.StructBlockFactory):
    text = factory.LazyAttribute(fake_paragraph)

    class Meta:
        model = TextBlock


class InstrumentFactory(BasePageFactory):
    title = factory.LazyAttribute(fake_title)
    type = factory.Iterator([BasicKnowledge.LANGUAGE_COMMUNICATION, BasicKnowledge.SOCIETY, BasicKnowledge.INTERDISCIPLINARY])

    class Meta:
        model = BasicKnowledge

    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        kwargs['parent'] = Site.objects.get(is_default_site=True).root_page
        return super()._create(model_class, *args, **kwargs)



class BasicKnowledgeBlockFactory(wagtail_factories.StructBlockFactory):
    description = factory.LazyAttribute(fake_paragraph)
    basic_knowledge = factory.SubFactory(InstrumentFactory)

    class Meta:
        model = BasicKnowledgeBlock


class ImageUrlBlockFactory(wagtail_factories.StructBlockFactory):
    title = fake_title()
    url = factory.LazyAttribute(lambda x: 'https://picsum.photos/600/400/?random')

    class Meta:
        model = ImageUrlBlock


class LinkBlockFactory(wagtail_factories.StructBlockFactory):
    text = fake_title()
    url = factory.LazyAttribute(lambda x: 'https://picsum.photos/600/400/?random')

    class Meta:
        model = LinkBlock


class AssignmentBlockFactory(wagtail_factories.StructBlockFactory):
    class Meta:
        model = AssignmentBlock

    @classmethod
    def _build(cls, model_class, *args, **kwargs):
        block = model_class()
        return blocks.StructValue(
            block,
            # todo: build in a more generic fashion
            [
                (name, kwargs['assignment']) for name, child_block in block.child_blocks.items()
            ],
        )


class VideoBlockFactory(wagtail_factories.StructBlockFactory):
    url = factory.LazyAttribute(lambda x: 'https://www.youtube.com/watch?v=lO9d-AJai8Q')

    class Meta:
        model = VideoBlock


block_types = ['text_block', 'basic_knowledge', 'student_entry', 'image_url_block', 'solution']


class ContentBlockFactory(BasePageFactory):
    class Meta:
        model = ContentBlock

    type = factory.LazyAttribute(lambda x: random.choice(['normal', 'base_communication', 'task', 'base_society']))

    contents = wagtail_factories.StreamFieldFactory({
        'text_block': TextBlockFactory,
        'basic_knowledge': BasicKnowledgeBlockFactory,
        'assignment': AssignmentBlockFactory,
        'image_block': wagtail_factories.ImageChooserBlockFactory,
        'image_url_block': ImageUrlBlockFactory,
        'link_block': LinkBlockFactory,
        'video_block': VideoBlockFactory,
        'solution': TextBlockFactory
    })

    @classmethod
    def stream_field_magic(cls, module, kwargs, stream_field_name):
        if stream_field_name in kwargs:
            """ 
            stream_field_name is most likely 'contents'
            this means: if there is a property named contents, us the defined ones in this block.
            otherwise, go into the other block and randomize the contents
            """
            for idx, resource in enumerate(kwargs[stream_field_name]):
                value = resource['value']
                block_type = resource['type']

                if block_type == 'assignment':
                    user = get_user_model().objects.first()
                    assignment = Assignment.objects.create(
                        title=value['title'],
                        assignment=value['assignment'],
                        owner=user,
                        module=module
                    )
                    kwargs['{}__{}__{}__{}'.format(stream_field_name, idx, block_type, 'assignment')] = assignment
                else:
                    for jdx, field in enumerate(value):

                        if block_type == 'text_block':
                            kwargs['{}__{}__{}__{}'.format(stream_field_name, idx, block_type, field)] = RichText(
                                value[field])
                        elif block_type == 'solution':
                            kwargs['{}__{}__{}__{}'.format(stream_field_name, idx, block_type, field)] = RichText(
                                value[field])
                        elif block_type == 'basic_knowledge':
                            if field == 'description':
                                kwargs[
                                    '{}__{}__{}__{}'.format(stream_field_name, idx, block_type, field)] = RichText(
                                    value[field])
                            else:
                                kwargs[
                                    '{}__{}__{}__{}'.format(stream_field_name, idx, block_type,
                                                            field)] = 'https://google.ch'
                        elif block_type == 'image_url_block':
                            kwargs[
                                '{}__{}__{}__{}'.format(stream_field_name, idx, block_type, field)] = value[field]

                        else:
                            kwargs[
                                '{}__{}__{}__{}'.format(stream_field_name, idx, block_type, field)] = value[field]

            del kwargs[stream_field_name]
        else:  # random contents from generator
            for i in range(0, random.randint(3, 7)):
                block_type = random.choice(block_types)
                if block_type == 'text_block':
                    kwargs['{}__{}__{}__{}'.format(stream_field_name, i, 'text_block', 'text')] = RichText(
                        fake_paragraph())
                elif block_type == 'basic_knowledge':
                    kwargs['{}__{}__{}__{}'.format(stream_field_name, i, 'basic_knowledge', 'description')] = RichText(
                        fake_paragraph())
                elif block_type == 'assignment':
                    kwargs['{}__{}__{}__{}'.format(stream_field_name, i, 'assignment', 'task_text')] = RichText(
                        fake_paragraph())
                elif block_type == 'image_url_block':
                    kwargs[
                        '{}__{}__{}__{}'.format(stream_field_name, i, 'image_url_block', 'title')] = fake_paragraph()
                    kwargs[
                        '{}__{}__{}__{}'.format(stream_field_name, i, 'image_url_block',
                                                'url')] = 'https://picsum.photos/400/?random={}'.format(
                        ''.join(random.choice('abcdefghiklmn') for _ in range(6)))
                elif block_type == 'solution':
                    kwargs['{}__{}__{}__{}'.format(stream_field_name, i, 'solution', 'text')] = RichText(
                        fake_paragraph())

    @classmethod
    def create(cls, module, **kwargs):
        cls.stream_field_magic(module, kwargs, 'contents')
        return cls._generate(CREATE_STRATEGY, kwargs)
