import datetime
import json
import logging
import re
import urllib

import requests_cache
from django.core.files.images import ImageFile
from django.forms.utils import ErrorList
from wagtail import blocks
from wagtail.blocks.struct_block import StructBlockValidationError
from wagtail.contrib.table_block.blocks import TableBlock
from wagtail.images.blocks import ImageChooserBlock
from wagtail.images.models import Image
from wagtail.models import Collection

from maps_utils.blocks import MapFeatureCollectionBlock, MapPointBlock
from shared.const import RICH_TEXT_DEFAULT_FEATURES

logger = logging.getLogger(__name__)


class GalleryBlock(blocks.StructBlock):
    gallery_items = blocks.ListBlock(
        ImageChooserBlock(label="obrázek", required=True),
        label="Galerie",
        icon="image",
        group="ostatní",
    )

    class Meta:
        label = "Galerie"
        icon = "image"
        template = "styleguide/2.3.x/blocks/gallery_block.html"


class FigureBlock(blocks.StructBlock):
    img = ImageChooserBlock(label="Obrázek", required=True)
    caption = blocks.TextBlock(label="Popisek", required=False)

    class Meta:
        label = "Obrázek"
        icon = "image"
        template = "styleguide/2.3.x/blocks/figure_block.html"


class MenuItemBlock(blocks.StructBlock):
    title = blocks.CharBlock(label="Titulek", required=True)
    page = blocks.PageChooserBlock(label="Stránka", required=False)
    link = blocks.URLBlock(label="Odkaz", required=False)

    class Meta:
        label = "Položka v menu"
        template = "styleguide/2.3.x/menu_item.html"

    def clean(self, value):
        errors = {}

        if value["page"] and value["link"]:
            errors["page"] = ErrorList(
                ["Stránka nemůže být vybrána současně s odkazem."]
            )
            errors["link"] = ErrorList(
                ["Odkaz nemůže být vybrán současně se stránkou."]
            )
        if errors:
            raise StructBlockValidationError(errors)
        return super().clean(value)


class MenuParentBlock(blocks.StructBlock):
    title = blocks.CharBlock(label="Titulek", required=True)
    menu_items = blocks.ListBlock(
        MenuItemBlock(),
    )

    class Meta:
        label = "Podmenu"
        template = "styleguide/2.3.x/menu_parent.html"


class ProgramItemBlock(blocks.StructBlock):
    title = blocks.CharBlock(label="Název", required=True)
    completion_percentage = blocks.IntegerBlock(
        label="Procento dokončení", required=True
    )
    issue_link = blocks.URLBlock(label="Odkaz na Redmine issue", required=False)


class YouTubeVideoBlock(blocks.StructBlock):
    poster_image = ImageChooserBlock(
        label="Náhled videa (automatické pole)",
        required=False,
        help_text="Není třeba vyplňovat, náhled bude " "dohledán automaticky.",
    )
    video_url = blocks.URLBlock(
        label="Odkaz na video",
        required=False,
        help_text="Odkaz na YouTube video bude automaticky "
        "zkonvertován na ID videa a NEBUDE uložen.",
    )
    video_id = blocks.CharBlock(
        label="ID videa (automatické pole)",
        required=False,
        help_text="Není třeba vyplňovat, bude automaticky " "načteno z odkazu.",
    )

    class Meta:
        label = "YouTube video"
        icon = "media"
        template = "styleguide/2.3.x/blocks/video_block.html"

    def clean(self, value):
        errors = {}

        if not value["video_url"] and not value["video_id"]:
            errors["video_url"] = ErrorList(["Zadejte prosím odkaz na YouTube video."])

        if value["video_url"]:
            if not value["video_url"].startswith("https://youtu.be") and not value[
                "video_url"
            ].startswith("https://www.youtube.com"):
                errors["video_url"] = ErrorList(
                    [
                        'Odkaz na video musí začínat "https://www.youtube.com" '
                        'nebo "https://youtu.be"'
                    ]
                )

        if value["video_id"]:
            if not re.match("^[A-Za-z0-9_-]{11}$", value["video_id"]):
                errors["video_url"] = ErrorList(
                    ["Formát ID YouTube videa není validní"]
                )

        if errors:
            raise StructBlockValidationError(errors)
        return super().clean(value)

    def get_prep_value(self, value):
        value = super().get_prep_value(value)

        if value["video_url"]:
            value["video_id"] = self.convert_youtube_link_to_video_id(
                value["video_url"]
            )
            value["poster_image"] = self.get_wagtail_image_id_for_youtube_poster(
                value["video_id"]
            )

        value["video_url"] = ""

        return value

    @staticmethod
    def convert_youtube_link_to_video_id(url):
        reg_str = (
            "((?<=(v|V)/)|(?<=youtu\.be/)|(?<=youtube\.com/watch(\?|\&)v=)"
            "|(?<=embed/))([\w-]+)"
        )
        search_result = re.search(reg_str, url)

        if search_result:
            return search_result.group(0)

        logger.warning(
            "Nepodařilo se získat video ID z YouTube URL", extra={"url": url}
        )
        return ""

    @classmethod
    def get_wagtail_image_id_for_youtube_poster(cls, video_id) -> int or None:
        image_url = "https://img.youtube.com/vi/{}/hqdefault.jpg".format(video_id)

        img_path = "/tmp/{}.jpg".format(video_id)
        urllib.request.urlretrieve(image_url, img_path)
        file = ImageFile(open(img_path, "rb"), name=img_path)

        return cls.get_image_id(file, "YT_poster_v_{}".format(video_id))

    @classmethod
    def get_image_id(cls, file: ImageFile, image_title: str) -> int:
        try:
            image = Image.objects.get(title=image_title)
        except Image.DoesNotExist:
            image = Image(
                title=image_title, file=file, collection=cls.get_posters_collection()
            )
            image.save()
        return image.id

    @staticmethod
    def get_posters_collection() -> Collection:
        collection_name = "YouTube nahledy"

        try:
            collection = Collection.objects.get(name=collection_name)
        except Collection.DoesNotExist:
            root_collection = Collection.get_first_root_node()
            collection = root_collection.add_child(name=collection_name)

        return collection


class CardBlock(blocks.StructBlock):
    img = ImageChooserBlock(label="Obrázek", required=False)
    elevation = blocks.IntegerBlock(
        label="Velikost stínu",
        min_value=0,
        max_value=21,
        help_text="0 = žádný stín, 21 = maximální stín",
        default=2,
    )
    headline = blocks.TextBlock(label="Titulek", required=False)
    hoveractive = blocks.BooleanBlock(
        label="Zvýraznit stín na hover",
        default=False,
        help_text="Pokud je zapnuto, stín se zvýrazní, když na kartu uživatel najede myší.",
        required=False,
    )
    content = blocks.StreamBlock(
        label="Obsah",
        local_blocks=[
            (
                "text",
                blocks.RichTextBlock(
                    label="Textový editor", features=RICH_TEXT_DEFAULT_FEATURES
                ),
            ),
            ("table", TableBlock(template="shared/blocks/table_block.html")),
            ("figure", FigureBlock()),
            ("youtube", YouTubeVideoBlock()),
            ("map_point", MapPointBlock(label="Špendlík na mapě")),
            ("map_collection", MapFeatureCollectionBlock(label="Mapová kolekce")),
        ],
        required=False,
    )
    page = blocks.PageChooserBlock(label="Stránka", required=False)
    link = blocks.URLBlock(label="Odkaz", required=False)

    class Meta:
        label = "Karta"
        icon = "form"
        template = "styleguide/2.3.x/blocks/card_block.html"

    def clean(self, value):
        errors = {}

        if value["page"] and value["link"]:
            errors["page"] = ErrorList(
                ["Stránka nemůže být vybrána současně s odkazem."]
            )
            errors["link"] = ErrorList(
                ["Odkaz nemůže být vybrán současně se stránkou."]
            )
        if errors:
            raise StructBlockValidationError(errors)

        return super().clean(value)


class ButtonBlock(blocks.StructBlock):
    title = blocks.CharBlock(label="Titulek", max_length=128, required=True)
    icon = blocks.CharBlock(
        label="Ikonka",
        max_length=128,
        required=False,
        help_text="Identifikátor ikonky ze styleguide (https://styleguide.pirati.cz/latest/?p=viewall-atoms-icons), např. ico--key.",
    )
    size = blocks.ChoiceBlock(
        choices=(("sm", "Malá"), ("base", "Střední"), ("lg", "Velká")),
        label="Velikost",
        default="base",
    )
    color = blocks.ChoiceBlock(
        choices=(
            ("black", "Černá"),
            ("white", "Bílá"),
            ("grey-125", "Světle šedá"),
            ("blue-300", "Modrá"),
            ("cyan-200", "Tyrkysová"),
            ("green-400", "Zelené"),
            ("violet-400", "Vínová"),
            ("red-600", "Červená"),
        ),
        label="Barva",
        default="base",
    )
    hoveractive = blocks.BooleanBlock(
        label="Animovat na hover",
        default=True,
        help_text="Pokud je zapnuto, tlačítko mění barvu, když na něj uživatel najede myší.",
        required=False,
    )
    mobile_fullwidth = blocks.BooleanBlock(
        label="Plná šířka na mobilních zařízeních",
        default=True,
        help_text="Pokud je zapnuto, tlačítko se na mobilních zařízeních roztáhne na plnou šířku.",
        required=False,
    )
    page = blocks.PageChooserBlock(label="Stránka", required=False)
    link = blocks.URLBlock(label="Odkaz", required=False)
    align = blocks.ChoiceBlock(
        choices=(
            ("auto", "Automaticky"),
            ("center", "Na střed"),
        ),
        label="Zarovnání",
        default="auto",
    )

    class Meta:
        label = "Tlačítko"
        icon = "code"
        template = "styleguide/2.3.x/blocks/button_block.html"

    def clean(self, value):
        errors = {}

        if value["page"] and value["link"]:
            errors["page"] = ErrorList(
                ["Stránka nemůže být vybrána současně s odkazem."]
            )
            errors["link"] = ErrorList(
                ["Odkaz nemůže být vybrán současně se stránkou."]
            )

        if not value["page"] and not value["link"]:
            errors["page"] = ErrorList(["Stránka nebo odkaz musí být vyplněna."])
            errors["link"] = ErrorList(["Stránka nebo odkaz musí být vyplněna."])

        if errors:
            raise StructBlockValidationError(errors)

        return super().clean(value)

    def get_context(self, value, parent_context=None):
        context = super().get_context(value, parent_context)

        if value["icon"]:
            context["icon_class"] = (
                value["icon"]
                if value["icon"].startswith("ico--")
                else f"ico--{value['icon']}"
            )
        else:
            context["icon_class"] = None

        return context


class ButtonGroupBlock(blocks.StructBlock):
    buttons = blocks.ListBlock(ButtonBlock(), label="Tlačítka")

    class Meta:
        label = "Skupina tlačítek"
        icon = "list-ul"
        template = "styleguide/2.3.x/blocks/button_group_block.html"


class FullSizeHeaderBlock(blocks.StructBlock):
    title = blocks.CharBlock(label="Titulek", required=True)
    image_background = ImageChooserBlock(label="Obrázek v pozadí", required=True)
    image_foreground = ImageChooserBlock(label="Obrázek v popředí", required=False)
    button_group = blocks.ListBlock(ButtonBlock(), label="Tlačítka")

    class Meta:
        template = "styleguide/2.3.x/blocks/full_size_header_block.html"
        icon = "placeholder"
        label = "Nadpis s obrázkem a tlačítky přes celou stránku"


class HeadlineBlock(blocks.StructBlock):
    headline = blocks.CharBlock(label="Headline", max_length=300, required=True)
    style = blocks.ChoiceBlock(
        choices=(
            ("head-alt-xl", "Bebas XL"),
            ("head-alt-lg", "Bebas L"),
            ("head-alt-md", "Bebas M"),
            ("head-alt-base", "Bebas base"),
            ("head-alt-sm", "Bebas SM"),
            ("head-alt-xs", "Bebas XS"),
            ("head-alt-2xs", "Bebas 2XS"),
            ("head-heavy-base", "Roboto base"),
            ("head-heavy-sm", "Roboto SM"),
            ("head-heavy-xs", "Roboto XS"),
            ("head-heavy-2xs", "Roboto 2XS"),
            ("head-allcaps-2xs", "Allcaps 2XS"),
            ("head-allcaps-3xs", "Allcaps 3XS"),
            ("head-allcaps-4xs", "Allcaps 4XS"),
            ("head-heavy-allcaps-2xs", "Allcaps heavy 2XS"),
            ("head-heavy-allcaps-3xs", "Allcaps heavy 3XS"),
            ("head-heavy-allcaps-4xs", "Allcaps heavy 4XS"),
        ),
        label="Styl",
        help_text="Náhled si prohlédněte na https://styleguide.pir-test.eu/latest/?p=viewall-atoms-text.",
        default="head-alt-md",
        required=True,
    )
    tag = blocks.ChoiceBlock(
        choices=(
            ("h1", "H1"),
            ("h2", "H2"),
            ("h3", "H3"),
            ("h4", "H4"),
            ("h5", "H5"),
            ("h6", "H6"),
        ),
        label="Úroveň nadpisu",
        help_text="Čím nižší číslo, tím vyšší úroveň.",
        required=True,
        default="h1",
    )
    align = blocks.ChoiceBlock(
        choices=(
            ("auto", "Automaticky"),
            ("center", "Na střed"),
        ),
        label="Zarovnání",
        default="auto",
        required=True,
    )

    def get_context(self, value, parent_context=None):
        context = super().get_context(value, parent_context)
        context["responsive_style"] = {
            "head-alt-xl": "head-alt-lg md:head-alt-xl",
            "head-alt-lg": "head-alt-md md:head-alt-lg",
            "head-alt-md": "head-alt-md",
            "head-alt-base": "head-alt-base",
            "head-alt-sm": "head-alt-sm",
            "head-alt-xs": "head-alt-xs",
            "head-alt-2xs": "head-alt-2xs",
            "head-heavy-base": "head-heavy-base",
            "head-heavy-sm": "head-heavy-sm",
            "head-heavy-xs": "head-heavy-xs",
            "head-heavy-2xs": "head-heavy-2xs",
            "head-allcaps-2xs": "head-allcaps-2xs",
            "head-allcaps-3xs": "head-allcaps-3xs",
            "head-allcaps-4xs": "head-allcaps-4xs",
            "head-heavy-allcaps-2xs": "head-heavy-allcaps-2xs",
            "head-heavy-allcaps-3xs": "head-heavy-allcaps-3xs",
            "head-heavy-allcaps-4xs": "head-heavy-allcaps-4xs",
        }[value["style"]]
        return context

    class Meta:
        label = "Headline"
        icon = "bold"
        template = "styleguide/2.3.x/blocks/headline_block.html"


class TwoColumnBlock(blocks.StructBlock):
    left_column_content = blocks.StreamBlock(
        label="Obsah levého sloupce",
        local_blocks=[
            (
                "text",
                blocks.RichTextBlock(
                    label="Textový editor", features=RICH_TEXT_DEFAULT_FEATURES
                ),
            ),
            ("table", TableBlock(template="shared/blocks/table_block.html")),
            ("card", CardBlock()),
            ("figure", FigureBlock()),
            ("youtube", YouTubeVideoBlock()),
            ("map_point", MapPointBlock(label="Špendlík na mapě")),
            ("map_collection", MapFeatureCollectionBlock(label="Mapová kolekce")),
            ("button", ButtonBlock()),
            ("button_group", ButtonGroupBlock()),
        ],
        required=True,
    )
    right_column_content = blocks.StreamBlock(
        label="Obsah pravého sloupce",
        local_blocks=[
            (
                "text",
                blocks.RichTextBlock(
                    label="Textový editor", features=RICH_TEXT_DEFAULT_FEATURES
                ),
            ),
            ("table", TableBlock(template="shared/blocks/table_block.html")),
            ("card", CardBlock()),
            ("figure", FigureBlock()),
            ("youtube", YouTubeVideoBlock()),
            ("map_point", MapPointBlock(label="Špendlík na mapě")),
            ("map_collection", MapFeatureCollectionBlock(label="Mapová kolekce")),
            ("button", ButtonBlock()),
            ("button_group", ButtonGroupBlock()),
        ],
        required=True,
    )

    class Meta:
        label = "Dva sloupce"
        icon = "grip"
        template = "styleguide/2.3.x/blocks/two_column_block.html"


class ThreeColumnBlock(blocks.StructBlock):
    left_column_content = blocks.StreamBlock(
        label="Obsah levého sloupce",
        local_blocks=[
            (
                "text",
                blocks.RichTextBlock(
                    label="Textový editor", features=RICH_TEXT_DEFAULT_FEATURES
                ),
            ),
            ("table", TableBlock(template="shared/blocks/table_block.html")),
            ("card", CardBlock()),
            ("figure", FigureBlock()),
            ("youtube", YouTubeVideoBlock()),
            ("map_point", MapPointBlock(label="Špendlík na mapě")),
            ("map_collection", MapFeatureCollectionBlock(label="Mapová kolekce")),
            ("button", ButtonBlock()),
            ("button_group", ButtonGroupBlock()),
        ],
        required=True,
    )
    middle_column_content = blocks.StreamBlock(
        label="Obsah prostředního sloupce",
        local_blocks=[
            (
                "text",
                blocks.RichTextBlock(
                    label="Textový editor", features=RICH_TEXT_DEFAULT_FEATURES
                ),
            ),
            ("table", TableBlock(template="shared/blocks/table_block.html")),
            ("card", CardBlock()),
            ("figure", FigureBlock()),
            ("youtube", YouTubeVideoBlock()),
            ("map_point", MapPointBlock(label="Špendlík na mapě")),
            ("map_collection", MapFeatureCollectionBlock(label="Mapová kolekce")),
            ("button", ButtonBlock()),
            ("button_group", ButtonGroupBlock()),
        ],
        required=True,
    )
    right_column_content = blocks.StreamBlock(
        label="Obsah pravého sloupce",
        local_blocks=[
            (
                "text",
                blocks.RichTextBlock(
                    label="Textový editor", features=RICH_TEXT_DEFAULT_FEATURES
                ),
            ),
            ("table", TableBlock(template="shared/blocks/table_block.html")),
            ("card", CardBlock()),
            ("figure", FigureBlock()),
            ("youtube", YouTubeVideoBlock()),
            ("map_point", MapPointBlock(label="Špendlík na mapě")),
            ("map_collection", MapFeatureCollectionBlock(label="Mapová kolekce")),
            ("button", ButtonBlock()),
            ("button_group", ButtonGroupBlock()),
        ],
        required=True,
    )

    class Meta:
        label = "Tři sloupce"
        icon = "grip"
        template = "styleguide/2.3.x/blocks/three_column_block.html"


class ImageBannerBlock(blocks.StructBlock):
    image = ImageChooserBlock(
        label="Obrázek",
        required=True,
    )
    headline = blocks.CharBlock(label="Headline", max_length=128, required=True)
    content = blocks.StreamBlock(
        label="Obsah pravého sloupce",
        local_blocks=[
            (
                "text",
                blocks.RichTextBlock(
                    label="Textový editor",
                    features=(
                        "h2",
                        "h3",
                        "h4",
                        "h5",
                        "bold",
                        "italic",
                        "ol",
                        "ul",
                        "hr",
                        "link",
                        "document-link",
                        "superscript",
                        "subscript",
                        "strikethrough",
                        "blockquote",
                    ),
                ),
            ),
            ("button", ButtonBlock()),
            ("button_group", ButtonGroupBlock()),
        ],
        required=False,
    )

    class Meta:
        label = "Obrázkový banner"
        icon = "image"
        template = "styleguide/2.3.x/blocks/image_banner_block.html"


class CardLinkBlockMixin(blocks.StructBlock):
    """
    Shared mixin for cards, which vary in templates and the types of pages
    they're allowed to link to.
    """

    image = ImageChooserBlock(label="Obrázek")
    title = blocks.CharBlock(label="Titulek", required=True)
    text = blocks.RichTextBlock(label="Krátký text pod nadpisem", required=False)

    page = blocks.PageChooserBlock(
        label="Stránka",
        page_type=[],
        required=False,
    )
    link = blocks.URLBlock(label="Odkaz", required=False)

    class Meta:
        # template = ""
        icon = "link"
        label = "Karta s odkazem"

    def clean(self, value):
        errors = {}

        if value["page"] and value["link"]:
            errors["page"] = ErrorList(
                ["Stránka nemůže být vybrána současně s odkazem."]
            )
            errors["link"] = ErrorList(
                ["Odkaz nemůže být vybrán současně se stránkou."]
            )
        elif not value["page"] and not value["link"]:
            errors["page"] = ErrorList(["Zvolte stránku nebo vyplňte odkaz."])
            errors["link"] = ErrorList(["Vyplňte odkaz nebo zvolte stránku."])
        if errors:
            raise StructBlockValidationError(errors)
        return super().clean(value)


class CardLinkWithHeadlineBlockMixin(blocks.StructBlock):
    headline = blocks.CharBlock(label="Titulek bloku", required=False)
    card_items = blocks.ListBlock(CardLinkBlockMixin(), label="Karty s odkazy")

    class Meta:
        # template = ""
        icon = "link"
        label = "Karty odkazů s nadpisem"


class ChartDataset(blocks.StructBlock):
    label = blocks.CharBlock(
        label="Označení zdroje dat",
        max_length=120,
    )

    data = blocks.ListBlock(
        blocks.IntegerBlock(),
        label="Data",
        default=[0],
    )

    class Meta:
        label = "Zdroj dat"


def get_redmine_projects():
    session = requests_cache.CachedSession(
        "redmine_cache",
        expire_after=datetime.timedelta(hours=1),
    )

    projects = session.get("https://redmine.pirati.cz/projects.json?limit=10000")
    projects.raise_for_status()
    projects = projects.json()["projects"]

    return [(project["id"], project["name"]) for project in projects]


class ChartRedmineIssueDataset(blocks.StructBlock):
    projects = blocks.MultipleChoiceBlock(
        label="Projekty", choices=get_redmine_projects
    )

    is_open = blocks.BooleanBlock(
        label="Jen otevřené",
        required=False,
    )
    is_closed = blocks.BooleanBlock(
        label="Jen uzavřené",
        required=False,
    )

    created_on = blocks.CharBlock(
        label="Filtr pro datum vytvoření",
        max_length=128,
        help_text="Např. >=2022-01-01, pro rozsah dat ><2022-01-01|2022-12-31. Více informací na pi2.cz/redmine-api",
        required=False,
    )
    updated_on = blocks.CharBlock(
        label="Filtr pro datum aktualizace",
        max_length=128,
        help_text="Např. <=2023-01-01. Více informací na pi2.cz/redmine-api",
        required=False,
    )

    issue_label = blocks.CharBlock(
        label="Označení úkolů uvnitř grafu",
        max_length=128,
        required=True,
    )

    def _get_issues_url(self, value):
        url = "https://redmine.pirati.cz/issues.json"
        params = [
            ("sort", "created_on"),
            ("limit", "100"),
        ]

        if "is_open" in value and "is_closed" in value:
            params.append(("status_id", "*"))
        elif "is_open" in value:
            params.append(("status_id", "open"))
        elif "is_closed" in value:
            params.append(("status_id", "closed"))

        for string_filter in ("created_on", "updated_on"):
            if value.get(string_filter, "") != "":
                params.append((string_filter, value[string_filter]))

        is_first = True

        for param_set in params:
            param, param_value = param_set

            url += "?" if is_first else "&"
            url += f"{param}={urllib.parse.quote(param_value)}"

            is_first = False

        return url

    def _get_parsed_issues(self, value, issues_url) -> tuple:
        session = requests_cache.CachedSession(
            "redmine_cache",
            expire_after=datetime.timedelta(days=14),
        )

        issues_response = session.get(issues_url)
        issues_response.raise_for_status()
        issues_response = issues_response.json()

        collected_issues = issues_response["issues"]
        offset = 0

        while issues_response["total_count"] - offset > len(issues_response["issues"]):
            offset += 100

            issues_response = session.get(f"{issues_url}&offset={offset}")
            issues_response.raise_for_status()
            issues_response = issues_response.json()

            collected_issues += issues_response["issues"]

        labels = []

        for issue in collected_issues:
            created_on_date = issue["created_on"].split("T")[0]

            if created_on_date in labels:
                continue

            labels.append(created_on_date)

        data = [0] * len(labels)

        current_issue_count = 0
        current_label = labels[0]

        ending_position = len(collected_issues) - 1

        for position, issue in enumerate(
            collected_issues
        ):  # Assume correct sorting order
            created_on_date = issue["created_on"].split("T")[0]

            if current_label != created_on_date or position == ending_position:
                data[
                    labels.index(current_label)
                ] = current_issue_count  # Assume labels are unique
                current_label = created_on_date

                if position != ending_position:
                    current_issue_count = 0
                else:
                    data[labels.index(current_label)] = 1
                    break

            current_issue_count += 1

        return labels, data

    def get_context(self, value) -> list:
        context = super().get_context(value)

        issues_url = self._get_issues_url(value)
        context["parsed_issues"] = self._get_parsed_issues(value, issues_url)

        return context

    class Meta:
        label = "Zdroj dat z Redmine (úkoly)"


class ChartBlock(blocks.StructBlock):
    title = blocks.CharBlock(
        label="Název",
        max_length=120,
    )
    chart_type = blocks.ChoiceBlock(
        label="Typ",
        choices=[
            ("bar", "Graf se sloupci"),
            ("horizontalBar", "Graf s vodorovnými sloupci"),
            ("pie", "Koláčový graf"),
            ("doughnut", "Donutový graf"),
            ("polarArea", "Graf polární oblasti"),
            ("radar", "Radarový graf"),
            ("line", "Graf s liniemi"),
        ],
        default="bar",
    )

    local_labels = blocks.ListBlock(
        blocks.CharBlock(
            max_length=40,
            label="Skupina",
        ),
        default=[],
        blank=True,
        required=False,
        collapsed=True,
        label="Místně definované skupiny",
    )
    local_datasets = blocks.ListBlock(
        ChartDataset(),
        default=[],
        blank=True,
        required=False,
        collapsed=True,
        label="Místní zdroje dat",
    )

    redmine_issue_datasets = blocks.ListBlock(
        ChartRedmineIssueDataset(label="Redmine úkoly"),
        default=[],
        blank=True,
        required=False,
        label="Zdroje dat z Redmine (úkoly)",
    )

    def get_context(self, value, parent_context=None):
        context = super().get_context(value, parent_context=parent_context)

        datasets = []
        labels = []

        if len(value["local_datasets"]) != 0:
            labels = value["local_labels"]

            for dataset in value["local_datasets"]:
                dataset = dict(dataset)

                datasets.append(
                    {
                        "label": dataset["label"],
                        "data": [item for item in dataset["data"]],
                    }
                )
        elif len(value["redmine_issue_datasets"]) != 0:
            for dataset_wrapper in value["redmine_issue_datasets"]:
                single_label_set, data = ChartRedmineIssueDataset().get_context(
                    dataset_wrapper
                )["parsed_issues"]

                labels += single_label_set

                datasets = [{"label": dataset_wrapper["issue_label"], "data": data}]

        value["datasets"] = json.dumps(datasets)
        value["labels"] = json.dumps([label for label in labels])

        return context

    class Meta:
        # template = ""
        label = "Graf"
        icon = "form"
        help_text = """Všechny položky zdrojů dat se chovají jako sloupce.
Zobrazí se tolik definovaných sloupců, kolik existuje skupin."""


DEFAULT_CONTENT_BLOCKS = [
    (
        "text",
        blocks.RichTextBlock(
            label="Textový editor", features=RICH_TEXT_DEFAULT_FEATURES
        ),
    ),
    ("headline", HeadlineBlock()),
    ("table", TableBlock(template="shared/blocks/table_block.html")),
    ("gallery", GalleryBlock(label="Galerie")),
    ("figure", FigureBlock()),
    ("card", CardBlock()),
    ("two_columns", TwoColumnBlock()),
    ("three_columns", ThreeColumnBlock()),
    ("youtube", YouTubeVideoBlock(label="YouTube video")),
    ("map_point", MapPointBlock(label="Špendlík na mapě")),
    ("map_collection", MapFeatureCollectionBlock(label="Mapová kolekce")),
    ("button", ButtonBlock()),
    ("button_group", ButtonGroupBlock()),
    ("image_banner", ImageBannerBlock()),
]