from django.test import TestCase

from content_editor.models import SimpleNamespace  # types.SimpleNamespace
from feincms3.renderer import TemplatePluginRenderer
from feincms3.incubator.newregions import Regions, cached_render, matches


class Text(SimpleNamespace):
    pass


class Teaser(SimpleNamespace):
    subregion = "teasers"


class FAQ(SimpleNamespace):
    subregion = "faq"


class Command(SimpleNamespace):
    subregion = ""


class File(SimpleNamespace):
    pass


renderer = TemplatePluginRenderer()
renderer.register_string_renderer(Text, lambda plugin: plugin.text)
renderer.register_string_renderer(Teaser, lambda plugin: plugin.text)
renderer.register_string_renderer(FAQ, lambda plugin: plugin.text)
renderer.register_string_renderer(File, lambda plugin: plugin.text)
renderer.register_string_renderer(Command, "")


class MyRegions(Regions):
    def handle_teasers(self, items, context):
        yield '<div class="teasers">'
        while True:
            yield self.renderer.render_plugin_in_context(items.popleft(), context)
            if not items or not matches(items[0], plugins=(Teaser,)):
                break
        yield "</div>"

    def handle_faq(self, items, context):
        yield '<div class="faq">'
        while True:
            yield self.renderer.render_plugin_in_context(items.popleft(), context)
            if not items or not matches(
                items[0], plugins=(FAQ, File), subregions={"faq"}
            ):
                break
        yield "</div>"


class Test(TestCase):
    def test_enter_exit(self):
        regions = MyRegions.from_contents(
            contents={
                "main": [
                    Text(text="Text 1"),
                    Teaser(text="Teaser 1"),
                    Teaser(text="Teaser 2"),
                    Text(text="Text 2"),
                ]
            },
            renderer=renderer,
        )

        self.assertEqual(
            regions.render("main"),
            'Text 1<div class="teasers">Teaser 1Teaser 2</div>Text 2',
        )

    def test_subregion_at_end(self):
        regions = MyRegions.from_contents(
            contents={
                "main": [
                    Text(text="Text 1"),
                    Teaser(text="Teaser 1"),
                    Teaser(text="Teaser 2"),
                ]
            },
            renderer=renderer,
        )

        self.assertEqual(
            regions.render("main"), 'Text 1<div class="teasers">Teaser 1Teaser 2</div>'
        )

    def test_other_subregion(self):
        regions = MyRegions.from_contents(
            contents={
                "main": [
                    Text(text="Text 1"),
                    Teaser(text="Teaser 1"),
                    Teaser(text="Teaser 2"),
                    FAQ(text="Question"),
                ]
            },
            renderer=renderer,
        )

        self.assertEqual(
            regions.render("main"),
            'Text 1<div class="teasers">Teaser 1Teaser 2</div>'
            '<div class="faq">Question</div>',
        )

    def test_explicit_exit(self):
        regions = MyRegions.from_contents(
            contents={
                "main": [
                    Text(text="Text 1"),
                    Teaser(text="Teaser 1"),
                    Teaser(text="Teaser 2"),
                    Command(),
                    Command(),  # Second exit shouldn't change anything
                ]
            },
            renderer=renderer,
        )

        self.assertEqual(
            regions.render("main"), 'Text 1<div class="teasers">Teaser 1Teaser 2</div>'
        )

    def test_both_allowed(self):
        regions = MyRegions.from_contents(
            contents={
                "main": [
                    Text(text="Text 1"),
                    File(text="download1.pdf"),  # Allowed outside...
                    Command(subregion="faq"),
                    FAQ(text="Question"),
                    File(text="download2.pdf"),  # ...and inside the FAQ renderer
                    Text(text="Text 2"),  # Main renderer again.
                ]
            },
            renderer=renderer,
        )

        self.assertEqual(
            regions.render("main"),
            'Text 1download1.pdf<div class="faq">Questiondownload2.pdf</div>Text 2',
        )

    def test_restart_subregion(self):
        class RestartRegions(Regions):
            def handle_restart(self, items, context):
                first = True
                yield '<div class="stuff">'
                while True:
                    yield self.renderer.render_plugin_in_context(
                        items.popleft(), context
                    )
                    # Item isn't the first and explicitly specifies
                    # subregion="restart", restart subregion
                    if (
                        not first
                        and items
                        and matches(items[0], subregions={"restart"})
                    ):
                        break

                    first = False

                yield "</div>"

        restart_renderer = TemplatePluginRenderer()
        restart_renderer.register_string_renderer(Text, lambda plugin: plugin.text)
        restart_renderer.register_string_renderer(Command, "")

        regions = RestartRegions(
            contents={
                "main": [
                    Text(text="before"),
                    Command(subregion="restart"),
                    Text(text="first"),
                    Command(subregion="restart"),
                    Text(text="second"),
                    Command(subregion=""),
                    Text(text="after"),
                ]
            },
            renderer=restart_renderer,
        )

        self.assertEqual(
            regions.render("main"),
            'before<div class="stuff">first</div><div class="stuff">second</div>after',
        )

    def test_enter_exit_with_custom_default(self):
        class CustomDefaultRegions(MyRegions):
            def handle_default(self, items, context):
                yield '<div class="default">'
                yield from super().handle_default(items, context)
                yield "</div>"

        regions = CustomDefaultRegions.from_contents(
            contents={
                "main": [
                    Text(text="Text 1"),
                    Teaser(text="Teaser 1"),
                    Teaser(text="Teaser 2"),
                    Text(text="Text 2"),
                    Text(text="Text 3"),
                ]
            },
            renderer=renderer,
        )

        self.assertEqual(
            regions.render("main"),
            '<div class="default">Text 1</div>'
            '<div class="teasers">Teaser 1Teaser 2</div>'
            '<div class="default">Text 2Text 3</div>',
        )

    def test_cache(self):
        regions = MyRegions.from_contents(
            contents={"main": [Text(text="Stuff")]},
            renderer=renderer,
            decorator=cached_render(cache_key=lambda region: region, timeout=15),
        )

        output = regions.render("main")

        regions = MyRegions.from_contents(
            contents={},
            renderer=renderer,
            decorator=cached_render(cache_key=lambda region: region, timeout=15),
        )
        self.assertEqual(output, regions.render("main"))

@@ -7400,8 +7400,292 @@
 main%22))%0A
+%0A    def test_unknown_subregion(self):%0A        regions = MyRegions.from_contents(%0A            contents=%7B%22main%22: %5BText(text=%22Stuff%22), Command(subregion=%22unknown%22)%5D%7D,%0A            renderer=renderer,%0A        )%0A%0A        with self.assertRaises(KeyError):%0A            regions.render(%22main%22)%0A

Test what happens when encountering an unknown subregion