from shimoku.api.resources.reports.tabs_group import TabsGroup
from shimoku.utils import create_function_name

from shimoku.code_gen.business_code_gen.apps_code_gen.reports_code_gen.report_types_code_gen.code_gen_from_other import (
    code_gen_from_other_reports,
    delete_default_properties,
)
from shimoku.code_gen.utils_code_gen import code_gen_from_value
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from shimoku.code_gen.business_code_gen.apps_code_gen.reports_code_gen.code_gen_from_reports import (
        AppCodeGen,
    )


async def code_gen_tabs_and_other(self: "AppCodeGen", tree: dict) -> list[str]:
    """Generate code for tabs and other components.
    :param tree: tree of reports
    :return: list of code lines
    """
    code_lines: list[str] = []
    reports_ordered = sorted(
        tree["other"] + tree["tab_groups"], key=lambda x: x["order"]
    )
    for i, report in enumerate(reports_ordered):
        report_obj = report if not isinstance(report, dict) else report["tabs_group"]
        if len(report_obj["bentobox"]):
            if (
                self._actual_bentobox is None
                or self._actual_bentobox["bentoboxId"]
                != report_obj["bentobox"]["bentoboxId"]
            ):
                self._actual_bentobox = report_obj["bentobox"]

                cols_size = self._actual_bentobox["bentoboxSizeColumns"]
                rows_size = self._actual_bentobox["bentoboxSizeRows"]
                code_lines.extend(
                    [
                        "",
                        f"shimoku_client.plt.set_bentobox(cols_size={cols_size}, rows_size={rows_size})",
                    ]
                )
        elif self._actual_bentobox is not None:
            self._actual_bentobox = None
            code_lines.append("shimoku_client.plt.pop_out_of_bentobox()")

        if isinstance(report, dict):
            code_lines.extend(
                [
                    "",
                    f'tabs_group_{create_function_name(report["name"])}(shimoku_client)',
                ]
            )
        else:
            code_lines.extend(await code_gen_from_other_reports(self, report))

        if i == len(reports_ordered) - 1 and self._actual_bentobox is not None:
            self._actual_bentobox = None
            code_lines.append("shimoku_client.plt.pop_out_of_bentobox()")

    return code_lines


async def code_gen_from_tabs_group(
    self: "AppCodeGen", tree: dict, is_last: bool = False
) -> list[str]:
    """Generate code for a tabs group.
    :param tree: tree of reports
    :param is_last: whether the tabs group is the last one
    :return: list of code lines
    """
    code_lines = []
    tabs_keys = list(tree["tabs"].keys())
    if len(tabs_keys) == 0:
        return ["pass"]
    tabs_group: TabsGroup = tree["tabs_group"]
    tabs_index = (tree["name"], tabs_keys[0])
    parent_tabs_index = tree["parent_tabs_index"]
    properties = delete_default_properties(
        tabs_group["properties"], TabsGroup.default_properties
    )
    del properties["hash"]
    if "tabs" in properties:
        del properties["tabs"]
    if "variant" in properties:
        properties["just_labels"] = True
        del properties["variant"]

    for tab in tree["tabs"]:
        code_lines.extend(
            [
                "",
                f"def tab_{create_function_name(tabs_index[0])}_{create_function_name(tab)}():",
            ]
        )
        # tab_code = await code_gen_tabs_functions(tree['tabs'][tab]['tab_groups'])
        tab_code = await code_gen_tabs_and_other(self, tree["tabs"][tab])
        if not tab_code:
            tab_code = ["pass"]
        code_lines.extend([f"    {line}" for line in tab_code])

    code_lines.extend(
        [
            "",
            "shimoku_client.plt.set_tabs_index(",
            f'    tabs_index=("{tabs_index[0]}", "{tabs_index[1]}"), order={tabs_group["order"]}, ',
        ]
    )
    if tabs_group["sizeColumns"]:
        code_lines.append(f'    cols_size={tabs_group["sizeColumns"]},')
    if tabs_group["sizeRows"]:
        code_lines.append(f'    rows_size={tabs_group["sizeRows"]},')
    if tabs_group["sizePadding"]:
        code_lines.append(f'    padding="{tabs_group["sizePadding"]}",')
    if parent_tabs_index:
        code_lines.extend([f"    parent_tabs_index={parent_tabs_index},"])
    code_lines.extend(
        [f"    {k}={code_gen_from_value(v)}," for k, v in properties.items()]
    )
    code_lines.extend([")"])

    for tab in tree["tabs"]:
        code_lines.extend(["", f'shimoku_client.plt.change_current_tab("{tab}")'])
        code_lines.extend(
            [f"tab_{create_function_name(tabs_index[0])}_{create_function_name(tab)}()"]
        )

    if parent_tabs_index:
        if not is_last:
            code_lines.extend(
                [
                    "",
                    f'shimoku_client.plt.set_tabs_index(("{parent_tabs_index[0]}", "{parent_tabs_index[1]}"))',
                ]
            )
    else:
        code_lines.extend(["", "shimoku_client.plt.pop_out_of_tabs_group()"])

    return code_lines


async def code_gen_tabs_functions(self, path: str) -> list[str]:
    """Generate code for tabs groups functions.
    :return: list of code lines
    """
    code_lines = []
    if path not in self._code_gen_tree.all_tab_groups:
        return code_lines
    for tabs_group in self._code_gen_tree.all_tab_groups[path]:
        tab_code_lines = await code_gen_from_tabs_group(self, tabs_group)
        code_lines.extend(
            [
                "",
                f'def tabs_group_{create_function_name(tabs_group["name"])}'
                f"(shimoku_client: Client):",
                *["    " + line for line in tab_code_lines],
            ]
        )
    return code_lines
