"""
GUI Controller layer.
Event handling and migration logic execution.
"""
import os
import threading
import traceback
from tkinter import filedialog, messagebox

from .i18n import I18n
from .languages import get_extensions
from .migrator import Migrator
from .gui_model import ConversionConfig, ConversionState
from .gui_view import MigratorView


class MigrationController:
    """Controller: event handling and migration orchestration."""

    def __init__(self, view: MigratorView, i18n: I18n):
        self.view = view
        self.i18n = i18n
        self.state = ConversionState()

        self._bind_events()
        self.view.apply_language()

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

    def _bind_events(self):
        self.view.bind_browse_input(self._browse_input)
        self.view.bind_browse_output(self._browse_output)
        self.view.bind_run(self._start_migration)
        self.view.bind_cancel(self._cancel_migration)
        self.view.bind_clear_log(self.view.clear_log)
        self.view.bind_language_change(self._on_language_change)
        self.view.bind_source_lang_change(self._on_lang_pair_change)
        self.view.bind_target_lang_change(self._on_lang_pair_change)

    # ---- Event Handlers ----

    def _browse_input(self):
        folder = filedialog.askdirectory(title=self._t("browse_input_title"))
        if folder:
            self.view.input_var.set(folder)

    def _browse_output(self):
        folder = filedialog.askdirectory(title=self._t("browse_output_title"))
        if folder:
            self.view.output_var.set(folder)

    def _on_language_change(self, lang_code: str):
        self.i18n.lang = lang_code
        self.view.apply_language()

    def _on_lang_pair_change(self):
        self.view.update_ext_info()

    # ---- Validation ----

    def _validate(self) -> ConversionConfig | None:
        t = self._t
        src = self.view.source_lang_var.get()
        tgt = self.view.target_lang_var.get()
        inp = self.view.input_var.get().strip()
        out = self.view.output_var.get().strip()

        if not src:
            messagebox.showwarning("", t("err_no_source"))
            return None
        if not tgt:
            messagebox.showwarning("", t("err_no_target"))
            return None
        if src == tgt:
            messagebox.showwarning("", t("err_same_lang"))
            return None
        if not inp:
            messagebox.showwarning("", t("err_no_input"))
            return None
        if not out:
            messagebox.showwarning("", t("err_no_output"))
            return None

        return ConversionConfig(
            input_dir=inp,
            output_dir=out,
            source_lang=src,
            target_lang=tgt,
            api_key=self.view.api_key_var.get().strip(),
            model=self.view.get_selected_model_code(),
            encoding=self.view.encoding_var.get(),
            extra_instructions=self.view.extra_instructions_var.get().strip(),
            enable_resume=self.view.resume_var.get(),
            enable_context=self.view.context_var.get(),
            enable_ecosystem=self.view.ecosystem_var.get(),
        )

    # ---- Migration ----

    def _start_migration(self):
        config = self._validate()
        if not config:
            return

        # Check for source files first
        src_exts = get_extensions(config.source_lang)
        source_files = []
        for root, _dirs, files in os.walk(config.input_dir):
            for f in files:
                ext = os.path.splitext(f)[1].lower()
                if ext in [e.lower() for e in src_exts]:
                    source_files.append(f)

        if not source_files:
            messagebox.showwarning("", self._t("err_no_files"))
            return

        self.state.reset()
        self.state.is_running = True
        self.state.total_files = len(source_files)
        self.view.set_running_state(True)
        self.view.progress_var.set(0)

        thread = threading.Thread(
            target=self._run_migration, args=(config,), daemon=True
        )
        thread.start()

    def _cancel_migration(self):
        self.state.cancel_flag = True
        self.view.log(self._t("log_cancel_request"), "warning")

    def _run_migration(self, config: ConversionConfig):
        """Run migration in background thread."""
        t = self._t
        try:
            self._log_safe(t("log_start", src=config.source_lang, tgt=config.target_lang), "info")

            if config.enable_resume:
                self._log_safe(t("log_resume_enabled"), "info")
            if config.enable_context:
                self._log_safe(t("log_context_enabled"), "info")
            if config.enable_ecosystem:
                self._log_safe(t("log_ecosystem_enabled"), "info")

            self._log_safe(t("log_scanning"), "info")

            migrator = Migrator(
                api_key=config.api_key,
                model=config.model,
            )

            src_exts = get_extensions(config.source_lang)
            tgt_exts = get_extensions(config.target_lang)
            tgt_ext = tgt_exts[0] if tgt_exts else ".txt"

            results = migrator.migrate_folder(
                input_dir=config.input_dir,
                output_dir=config.output_dir,
                source_lang=config.source_lang,
                target_lang=config.target_lang,
                source_extensions=src_exts,
                target_extension=tgt_ext,
                extra_instructions=config.extra_instructions,
                on_progress=lambda f, i, n: (
                    self._log_safe(t("log_processing", i=i, n=n, file=f), "info"),
                    self._update_progress(i / n * 100),
                ),
                on_log=self._log_safe,
                cancel_check=lambda: self.state.cancel_flag,
                encoding=config.encoding,
                enable_resume=config.enable_resume,
                enable_context=config.enable_context,
                enable_ecosystem=config.enable_ecosystem,
            )

            # Log results from details
            for filename, status, info in results["details"]:
                if status == "OK":
                    self._log_safe(t("log_success", out=info), "success")
                elif status == "ERROR":
                    self._log_safe(t("log_error", err=info), "error")
                elif status == "CANCELLED":
                    pass  # handled below

            # Final summary
            s = results["success"]
            e = results["errors"]
            k = results["skipped"]
            r = results["resumed"]

            if self.state.cancel_flag:
                self._log_safe(t("status_cancelled"), "warning")
                self._set_status(t("status_cancelled"))
            else:
                summary = t("log_complete", s=s, e=e, k=k)
                if r > 0:
                    summary += f" | Resumed: {r}"
                self._log_safe(summary, "info")
                self._set_status(t("status_done"))

        except Exception as e:
            self._log_safe(f"Fatal error: {str(e)}", "error")
            traceback.print_exc()
        finally:
            self.state.is_running = False
            self.view.root.after(0, lambda: self.view.set_running_state(False))

    # ---- Thread-safe UI updates ----

    def _log_safe(self, message: str, tag: str = "info"):
        self.view.root.after(0, lambda: self.view.log(message, tag))

    def _update_progress(self, value: float):
        self.view.root.after(0, lambda: self.view.progress_var.set(value))

    def _set_status(self, text: str):
        self.view.root.after(0, lambda: self.view.status_var.set(text))
