"""
GUI View layer.
tkinter widget creation, layout, and styling only.
Event handling is bound via Controller.
"""
import tkinter as tk
from tkinter import ttk, scrolledtext
from typing import Callable, Dict

from .i18n import I18n, LANGUAGES as UI_LANGUAGES
from .languages import LANGUAGE_NAMES, get_extensions
from .gui_model import MODEL_OPTIONS


class MigratorView:
    """View: widget creation and layout."""

    def __init__(self, root: tk.Tk, i18n: I18n):
        self.root = root
        self.i18n = i18n
        self.root.geometry("900x800")
        self.root.minsize(750, 650)
        self.root.resizable(True, True)

        self._widgets: Dict[str, ttk.Widget] = {}

        # tkinter variables
        self.input_var = tk.StringVar()
        self.output_var = tk.StringVar()
        self.source_lang_var = tk.StringVar()
        self.target_lang_var = tk.StringVar()
        self.api_key_var = tk.StringVar()
        self.model_var = tk.StringVar(value=MODEL_OPTIONS[0][1])
        self.encoding_var = tk.StringVar(value="utf-8")
        self.extra_instructions_var = tk.StringVar()
        self.resume_var = tk.BooleanVar(value=True)
        self.context_var = tk.BooleanVar(value=True)
        self.ecosystem_var = tk.BooleanVar(value=True)
        self.progress_var = tk.DoubleVar(value=0)
        self.status_var = tk.StringVar()

        # UI language mapping
        lang_display = [f"{v}" for v in UI_LANGUAGES.values()]
        lang_codes = list(UI_LANGUAGES.keys())
        self._lang_code_map = dict(zip(lang_display, lang_codes))

        # Model display mapping
        self._model_display = [m[0] for m in MODEL_OPTIONS]
        self._model_code_map = {m[0]: m[1] for m in MODEL_OPTIONS}

        self._setup_styles()
        self._build_ui()

    def _t(self, key: str, **kwargs) -> str:
        return self.i18n.t(key, **kwargs)

    def _setup_styles(self):
        style = ttk.Style()
        style.theme_use("clam")
        style.configure("Title.TLabel", font=("Segoe UI", 14, "bold"), foreground="#1a5276")
        style.configure("Header.TLabel", font=("Segoe UI", 10, "bold"))
        style.configure("Run.TButton", font=("Segoe UI", 10, "bold"))
        style.configure("TLabelframe.Label", font=("Segoe UI", 9, "bold"))
        style.configure("Arrow.TLabel", font=("Segoe UI", 18, "bold"), foreground="#2980b9")

    def _build_ui(self):
        main = ttk.Frame(self.root, padding=12)
        main.pack(fill=tk.BOTH, expand=True)

        # --- Top bar: Title + UI Language ---
        top = ttk.Frame(main)
        top.pack(fill=tk.X, pady=(0, 10))

        self._widgets["title"] = ttk.Label(top, style="Title.TLabel")
        self._widgets["title"].pack(side=tk.LEFT)

        lang_frame = ttk.Frame(top)
        lang_frame.pack(side=tk.RIGHT)
        self._widgets["ui_lang_label"] = ttk.Label(lang_frame)
        self._widgets["ui_lang_label"].pack(side=tk.LEFT, padx=(0, 4))

        lang_display = list(self._lang_code_map.keys())
        lang_combo = ttk.Combobox(
            lang_frame, textvariable=tk.StringVar(value="English"),
            values=lang_display, width=12, state="readonly"
        )
        lang_combo.pack(side=tk.LEFT)
        self._widgets["ui_lang_combo"] = lang_combo

        # --- Language Pair ---
        self._widgets["lang_frame"] = ttk.LabelFrame(main, padding=10)
        self._widgets["lang_frame"].pack(fill=tk.X, pady=(0, 8))
        lf = self._widgets["lang_frame"]

        self._widgets["source_lang_label"] = ttk.Label(lf, style="Header.TLabel")
        self._widgets["source_lang_label"].grid(row=0, column=0, sticky=tk.W, pady=2)

        lang_list = [""] + LANGUAGE_NAMES
        self._widgets["source_lang_combo"] = ttk.Combobox(
            lf, textvariable=self.source_lang_var,
            values=lang_list, width=30, state="readonly"
        )
        self._widgets["source_lang_combo"].grid(row=0, column=1, sticky=tk.W, padx=8, pady=2)

        self._widgets["arrow_label"] = ttk.Label(lf, text="→", style="Arrow.TLabel")
        self._widgets["arrow_label"].grid(row=0, column=2, padx=12)

        self._widgets["target_lang_label"] = ttk.Label(lf, style="Header.TLabel")
        self._widgets["target_lang_label"].grid(row=0, column=3, sticky=tk.W, pady=2)

        self._widgets["target_lang_combo"] = ttk.Combobox(
            lf, textvariable=self.target_lang_var,
            values=lang_list, width=30, state="readonly"
        )
        self._widgets["target_lang_combo"].grid(row=0, column=4, sticky=tk.W, padx=8, pady=2)

        # Extensions info label
        self._widgets["ext_info"] = ttk.Label(lf, text="", foreground="#666666")
        self._widgets["ext_info"].grid(row=1, column=0, columnspan=5, sticky=tk.W, pady=(4, 0))

        # --- Folder Selection ---
        self._widgets["folder_frame"] = ttk.LabelFrame(main, padding=10)
        self._widgets["folder_frame"].pack(fill=tk.X, pady=(0, 8))
        ff = self._widgets["folder_frame"]

        self._widgets["input_label"] = ttk.Label(ff, style="Header.TLabel")
        self._widgets["input_label"].grid(row=0, column=0, sticky=tk.W, pady=2)
        ttk.Entry(ff, textvariable=self.input_var, width=55).grid(row=0, column=1, padx=8, pady=2)
        self._widgets["input_browse"] = ttk.Button(ff, width=10)
        self._widgets["input_browse"].grid(row=0, column=2, pady=2)

        self._widgets["output_label"] = ttk.Label(ff, style="Header.TLabel")
        self._widgets["output_label"].grid(row=1, column=0, sticky=tk.W, pady=2)
        ttk.Entry(ff, textvariable=self.output_var, width=55).grid(row=1, column=1, padx=8, pady=2)
        self._widgets["output_browse"] = ttk.Button(ff, width=10)
        self._widgets["output_browse"].grid(row=1, column=2, pady=2)

        # --- API Settings ---
        self._widgets["api_frame"] = ttk.LabelFrame(main, padding=10)
        self._widgets["api_frame"].pack(fill=tk.X, pady=(0, 8))
        af = self._widgets["api_frame"]

        self._widgets["api_key_label"] = ttk.Label(af, style="Header.TLabel")
        self._widgets["api_key_label"].grid(row=0, column=0, sticky=tk.W, pady=2)
        self._widgets["api_key_entry"] = ttk.Entry(af, textvariable=self.api_key_var, width=55, show="*")
        self._widgets["api_key_entry"].grid(row=0, column=1, padx=8, pady=2)

        self._widgets["model_label"] = ttk.Label(af, style="Header.TLabel")
        self._widgets["model_label"].grid(row=1, column=0, sticky=tk.W, pady=2)
        self._widgets["model_combo"] = ttk.Combobox(
            af, values=self._model_display, width=35, state="readonly"
        )
        self._widgets["model_combo"].set(self._model_display[0])
        self._widgets["model_combo"].grid(row=1, column=1, sticky=tk.W, padx=8, pady=2)

        # --- Options ---
        self._widgets["options_frame"] = ttk.LabelFrame(main, padding=10)
        self._widgets["options_frame"].pack(fill=tk.X, pady=(0, 8))
        of = self._widgets["options_frame"]

        self._widgets["encoding_label"] = ttk.Label(of, style="Header.TLabel")
        self._widgets["encoding_label"].grid(row=0, column=0, sticky=tk.W, pady=2)
        ttk.Combobox(
            of, textvariable=self.encoding_var,
            values=["utf-8", "shift_jis", "euc-jp", "cp932", "latin-1", "cp1252", "ascii", "iso-8859-1"],
            width=15, state="readonly"
        ).grid(row=0, column=1, sticky=tk.W, padx=8, pady=2)

        self._widgets["extra_label"] = ttk.Label(of, style="Header.TLabel")
        self._widgets["extra_label"].grid(row=1, column=0, sticky=tk.W, pady=2)
        ttk.Entry(of, textvariable=self.extra_instructions_var, width=60).grid(
            row=1, column=1, columnspan=2, sticky=tk.EW, padx=8, pady=2
        )

        # Checkboxes row
        cb_frame = ttk.Frame(of)
        cb_frame.grid(row=2, column=0, columnspan=3, sticky=tk.W, pady=(6, 0))

        self._widgets["resume_cb"] = ttk.Checkbutton(
            cb_frame, variable=self.resume_var
        )
        self._widgets["resume_cb"].pack(side=tk.LEFT, padx=(0, 16))

        self._widgets["context_cb"] = ttk.Checkbutton(
            cb_frame, variable=self.context_var
        )
        self._widgets["context_cb"].pack(side=tk.LEFT, padx=(0, 16))

        self._widgets["ecosystem_cb"] = ttk.Checkbutton(
            cb_frame, variable=self.ecosystem_var
        )
        self._widgets["ecosystem_cb"].pack(side=tk.LEFT)

        # --- Run / Cancel / Progress ---
        btn_frame = ttk.Frame(main)
        btn_frame.pack(fill=tk.X, pady=(0, 8))

        self._widgets["run_btn"] = ttk.Button(btn_frame, style="Run.TButton", width=18)
        self._widgets["run_btn"].pack(side=tk.LEFT, padx=(0, 8))

        self._widgets["cancel_btn"] = ttk.Button(btn_frame, width=12, state=tk.DISABLED)
        self._widgets["cancel_btn"].pack(side=tk.LEFT, padx=(0, 8))

        self._widgets["clear_btn"] = ttk.Button(btn_frame, width=12)
        self._widgets["clear_btn"].pack(side=tk.LEFT)

        self._widgets["status_label"] = ttk.Label(btn_frame)
        self._widgets["status_label"].pack(side=tk.RIGHT)

        self._widgets["progress"] = ttk.Progressbar(
            main, variable=self.progress_var, maximum=100
        )
        self._widgets["progress"].pack(fill=tk.X, pady=(0, 8))

        # --- Log ---
        self._widgets["log_frame"] = ttk.LabelFrame(main, padding=8)
        self._widgets["log_frame"].pack(fill=tk.BOTH, expand=True)

        self.log_text = scrolledtext.ScrolledText(
            self._widgets["log_frame"], height=12, wrap=tk.WORD,
            font=("Consolas", 9), state=tk.DISABLED
        )
        self.log_text.pack(fill=tk.BOTH, expand=True)

        # Configure log text tags
        self.log_text.tag_configure("info", foreground="#2c3e50")
        self.log_text.tag_configure("success", foreground="#27ae60")
        self.log_text.tag_configure("error", foreground="#c0392b")
        self.log_text.tag_configure("warning", foreground="#e67e22")

    # --- Public API for Controller ---

    def apply_language(self):
        """Refresh all widget text from i18n."""
        t = self._t
        self.root.title(t("title"))
        self._widgets["title"].configure(text=t("title"))
        self._widgets["ui_lang_label"].configure(text=t("ui_lang"))
        self._widgets["lang_frame"].configure(text=t("lang_frame"))
        self._widgets["source_lang_label"].configure(text=t("source_lang"))
        self._widgets["target_lang_label"].configure(text=t("target_lang"))
        self._widgets["folder_frame"].configure(text=t("folder_frame"))
        self._widgets["input_label"].configure(text=t("input_folder"))
        self._widgets["output_label"].configure(text=t("output_folder"))
        self._widgets["input_browse"].configure(text=t("browse"))
        self._widgets["output_browse"].configure(text=t("browse"))
        self._widgets["api_frame"].configure(text=t("api_frame"))
        self._widgets["api_key_label"].configure(text=t("api_key"))
        self._widgets["model_label"].configure(text=t("model"))
        self._widgets["options_frame"].configure(text=t("options_frame"))
        self._widgets["encoding_label"].configure(text=t("encoding"))
        self._widgets["extra_label"].configure(text=t("extra_instructions"))
        self._widgets["resume_cb"].configure(text=t("resume"))
        self._widgets["context_cb"].configure(text=t("context"))
        self._widgets["ecosystem_cb"].configure(text=t("ecosystem"))
        self._widgets["run_btn"].configure(text=t("run"))
        self._widgets["cancel_btn"].configure(text=t("cancel"))
        self._widgets["clear_btn"].configure(text=t("clear_log"))
        self._widgets["log_frame"].configure(text=t("log_frame"))
        if not self.status_var.get():
            self.status_var.set(t("status_ready"))
        self._widgets["status_label"].configure(textvariable=self.status_var)

    def get_selected_model_code(self) -> str:
        display = self._widgets["model_combo"].get()
        return self._model_code_map.get(display, MODEL_OPTIONS[0][1])

    def update_ext_info(self):
        """Show file extensions for the selected source language."""
        src = self.source_lang_var.get()
        tgt = self.target_lang_var.get()
        parts = []
        if src:
            exts = get_extensions(src)
            parts.append(f"Source: {', '.join(exts)}")
        if tgt:
            exts = get_extensions(tgt)
            parts.append(f"Target ext: {exts[0] if exts else '?'}")
        self._widgets["ext_info"].configure(text="  |  ".join(parts))

    def set_running_state(self, running: bool):
        state_normal = tk.NORMAL
        state_disabled = tk.DISABLED
        if running:
            self._widgets["run_btn"].configure(state=state_disabled)
            self._widgets["cancel_btn"].configure(state=state_normal)
            self.status_var.set(self._t("status_running"))
        else:
            self._widgets["run_btn"].configure(state=state_normal)
            self._widgets["cancel_btn"].configure(state=state_disabled)

    def log(self, message: str, tag: str = "info"):
        self.log_text.configure(state=tk.NORMAL)
        self.log_text.insert(tk.END, message + "\n", tag)
        self.log_text.see(tk.END)
        self.log_text.configure(state=tk.DISABLED)

    def clear_log(self):
        self.log_text.configure(state=tk.NORMAL)
        self.log_text.delete("1.0", tk.END)
        self.log_text.configure(state=tk.DISABLED)

    # --- Event binding ---

    def bind_browse_input(self, cb: Callable):
        self._widgets["input_browse"].configure(command=cb)

    def bind_browse_output(self, cb: Callable):
        self._widgets["output_browse"].configure(command=cb)

    def bind_run(self, cb: Callable):
        self._widgets["run_btn"].configure(command=cb)

    def bind_cancel(self, cb: Callable):
        self._widgets["cancel_btn"].configure(command=cb)

    def bind_clear_log(self, cb: Callable):
        self._widgets["clear_btn"].configure(command=cb)

    def bind_language_change(self, cb: Callable):
        combo = self._widgets["ui_lang_combo"]

        def _on_change(_event):
            display = combo.get()
            code = self._lang_code_map.get(display, "en")
            cb(code)

        combo.bind("<<ComboboxSelected>>", _on_change)

    def bind_source_lang_change(self, cb: Callable):
        self._widgets["source_lang_combo"].bind("<<ComboboxSelected>>", lambda _: cb())

    def bind_target_lang_change(self, cb: Callable):
        self._widgets["target_lang_combo"].bind("<<ComboboxSelected>>", lambda _: cb())
