import textwrap
import tkinter as tk
from tkinter import font as tk_font
from tkinter import ttk

from thonny import get_workbench
from thonny.codeview import CodeView
from thonny.config_ui import ConfigurationPage
from thonny.ui_utils import create_string_var


class ThemeAndFontConfigurationPage(ConfigurationPage):
    def __init__(self, master):

        self._original_family = get_workbench().get_option("view.editor_font_family")
        self._original_size = get_workbench().get_option("view.editor_font_size")
        self._original_ui_theme = get_workbench().get_option("view.ui_theme")
        self._original_syntax_theme = get_workbench().get_option("view.syntax_theme")

        ConfigurationPage.__init__(self, master)

        self._family_variable = create_string_var(
            self._original_family, modification_listener=self._update_appearance
        )

        self._size_variable = create_string_var(
            self._original_size, modification_listener=self._update_appearance
        )

        self._ui_theme_variable = create_string_var(
            self._original_ui_theme, modification_listener=self._update_appearance
        )

        self._syntax_theme_variable = create_string_var(
            self._original_syntax_theme, modification_listener=self._update_appearance
        )

        ttk.Label(self, text="UI theme").grid(row=1, column=0, sticky="w", pady=(10, 0))
        self._ui_theme_combo = ttk.Combobox(
            self,
            exportselection=False,
            textvariable=self._ui_theme_variable,
            state="readonly",
            height=15,
            values=get_workbench().get_usable_ui_theme_names(),
        )
        self._ui_theme_combo.grid(row=2, column=0, sticky="nsew", padx=(0, 10))

        ttk.Label(self, text="Syntax theme").grid(
            row=1, column=1, sticky="w", pady=(10, 0)
        )
        self._syntax_theme_combo = ttk.Combobox(
            self,
            exportselection=False,
            textvariable=self._syntax_theme_variable,
            state="readonly",
            height=15,
            values=get_workbench().get_syntax_theme_names(),
        )
        self._syntax_theme_combo.grid(row=2, column=1, sticky="nsew", padx=(0, 10))

        ttk.Label(self, text="Editor font").grid(
            row=1, column=2, sticky="w", pady=(10, 0)
        )
        self._family_combo = ttk.Combobox(
            self,
            exportselection=False,
            state="readonly",
            height=15,
            textvariable=self._family_variable,
            values=self._get_families_to_show(),
        )
        self._family_combo.grid(row=2, column=2, sticky=tk.NSEW, padx=(0, 10))

        ttk.Label(self, text="Size").grid(row=1, column=3, sticky="w", pady=(10, 0))
        self._size_combo = ttk.Combobox(
            self,
            width=4,
            exportselection=False,
            textvariable=self._size_variable,
            state="readonly",
            height=15,
            values=[str(x) for x in range(3, 73)],
        )
        self._size_combo.grid(row=2, column=3, sticky="nsew")

        ttk.Label(self, text="Editor preview").grid(
            row=3, column=0, sticky="w", pady=(10, 0), columnspan=4
        )
        self._preview_codeview = CodeView(
            self,
            height=10,
            font="EditorFont",
            # relief="sunken",
            # borderwidth=1,
        )

        self._preview_codeview.set_content(
            textwrap.dedent(
                """
            def foo(bar):
                if bar is None: # This is a comment
                    print("The answer is", 33)
            
            unclosed_string = "blah, blah
            """
            ).strip()
        )
        self._preview_codeview.grid(
            row=4, column=0, columnspan=4, sticky=tk.NSEW, pady=(0, 5)
        )

        (
            ttk.Label(
                self, text="NB! Some style elements change only after restarting Thonny"
            ).grid(row=5, column=0, columnspan=4, sticky="w", pady=(0, 5))
        )

        self.columnconfigure(0, weight=1)
        self.columnconfigure(1, weight=1)
        self.columnconfigure(2, weight=1)
        self.columnconfigure(3, weight=1)
        self.rowconfigure(4, weight=1)

    def apply(self):
        # don't do anything, as preview already did the thing
        return

    def cancel(self):
        if (
            getattr(self._family_variable, "modified")
            or getattr(self._size_variable, "modified")
            or getattr(self._ui_theme_variable, "modified")
            or getattr(self._syntax_theme_variable, "modified")
        ):
            get_workbench().set_option("view.ui_theme", self._original_ui_theme)
            get_workbench().set_option("view.syntax_theme", self._original_syntax_theme)
            get_workbench().set_option("view.editor_font_size", self._original_size)
            get_workbench().set_option("view.editor_font_family", self._original_family)
            get_workbench().reload_themes()
            get_workbench().update_fonts()

    def _update_appearance(self):
        get_workbench().set_option("view.ui_theme", self._ui_theme_variable.get())
        get_workbench().set_option(
            "view.syntax_theme", self._syntax_theme_variable.get()
        )
        get_workbench().set_option(
            "view.editor_font_size", int(self._size_variable.get())
        )
        get_workbench().set_option(
            "view.editor_font_family", self._family_variable.get()
        )
        get_workbench().reload_themes()
        get_workbench().update_fonts()

    def _get_families_to_show(self):
        # In Linux, families may contain duplicates (actually different fonts get same names)
        return sorted(set(filter(lambda name: name[0].isalpha(), tk_font.families())))


def load_plugin() -> None:
    get_workbench().add_configuration_page(
        "Theme & Font", ThemeAndFontConfigurationPage
    )
