from __future__ import annotations

import tkinter as tk
from tkinter import ttk


HISTORY_TREE_COLUMNS = (
    "changed_at",
    "scope_label",
    "entity_label",
    "action_label",
    "user_display_name",
    "summary",
)

HISTORY_SCOPE_OPTIONS = [
    ("__all__", "history_filter_all_modules"),
    ("purchase_order", "menu_purchase_order"),
    ("costing", "menu_costing"),
    ("bom", "menu_bom"),
    ("tech_pack", "menu_tech_pack"),
    ("samples", "menu_samples"),
]


def _build_history_module(self, parent: ttk.Frame) -> None:
    parent.columnconfigure(0, weight=1)
    parent.rowconfigure(2, weight=1)

    header = ttk.Frame(parent)
    header.grid(row=0, column=0, sticky="ew")
    self.widget_text["history_section_title"] = ttk.Label(header, style="Section.TLabel")
    self.widget_text["history_section_title"].pack(anchor="w")
    self.widget_text["history_section_subtitle"] = ttk.Label(header, style="Muted.TLabel", wraplength=1120, justify="left")
    self.widget_text["history_section_subtitle"].pack(anchor="w", pady=(4, 0))

    filters = ttk.Frame(parent)
    filters.grid(row=1, column=0, sticky="ew", pady=(12, 14))
    filters.columnconfigure(7, weight=1)

    self.widget_text["history_scope_label"] = ttk.Label(filters)
    self.widget_text["history_scope_label"].grid(row=0, column=0, sticky="w", padx=(0, 6))
    self.history_scope_options_by_label = {
        self.translate_history_scope(key): key
        for key, _text_key in HISTORY_SCOPE_OPTIONS
    }
    self.history_scope_combo = ttk.Combobox(filters, textvariable=self.history_scope_var, state="readonly", width=18)
    self.history_scope_combo.grid(row=0, column=1, sticky="w")
    self.history_scope_combo.configure(values=list(self.history_scope_options_by_label))
    self.history_scope_var.set(self.translate_history_scope("__all__"))
    self.history_scope_combo.bind("<<ComboboxSelected>>", lambda _event: self.apply_history_filter())

    self.widget_text["history_user_label"] = ttk.Label(filters)
    self.widget_text["history_user_label"].grid(row=0, column=2, sticky="w", padx=(12, 6))
    self.history_user_entry = ttk.Entry(filters, textvariable=self.history_user_var, width=24)
    self.history_user_entry.grid(row=0, column=3, sticky="w")
    self.history_user_entry.bind("<Return>", self.on_history_search_submit)
    self.history_user_entry.bind("<KP_Enter>", self.on_history_search_submit)

    self.widget_text["history_keyword_label"] = ttk.Label(filters)
    self.widget_text["history_keyword_label"].grid(row=0, column=4, sticky="w", padx=(12, 6))
    self.history_keyword_entry = ttk.Entry(filters, textvariable=self.history_keyword_var, width=28)
    self.history_keyword_entry.grid(row=0, column=5, sticky="w")
    self.history_keyword_entry.bind("<Return>", self.on_history_search_submit)
    self.history_keyword_entry.bind("<KP_Enter>", self.on_history_search_submit)

    self.widget_text["history_date_from_label"] = ttk.Label(filters)
    self.widget_text["history_date_from_label"].grid(row=1, column=0, sticky="w", padx=(0, 6), pady=(10, 0))
    self.history_date_from_entry = ttk.Entry(filters, textvariable=self.history_date_from_var, width=12)
    self.history_date_from_entry.grid(row=1, column=1, sticky="w", pady=(10, 0))
    self.bind_date_entry_picker(self.history_date_from_entry, self.history_date_from_var)
    self.history_date_from_var.trace_add("write", lambda *_args: self.apply_history_filter())

    self.widget_text["history_date_to_label"] = ttk.Label(filters)
    self.widget_text["history_date_to_label"].grid(row=1, column=2, sticky="w", padx=(12, 6), pady=(10, 0))
    self.history_date_to_entry = ttk.Entry(filters, textvariable=self.history_date_to_var, width=12)
    self.history_date_to_entry.grid(row=1, column=3, sticky="w", pady=(10, 0))
    self.bind_date_entry_picker(self.history_date_to_entry, self.history_date_to_var)
    self.history_date_to_var.trace_add("write", lambda *_args: self.apply_history_filter())

    self.widget_text["history_refresh_button"] = ttk.Button(filters, command=self.refresh_history_module)
    self.widget_text["history_refresh_button"].grid(row=1, column=5, sticky="w", pady=(10, 0))

    table_frame = ttk.Frame(parent)
    table_frame.grid(row=2, column=0, sticky="nsew")
    table_frame.columnconfigure(0, weight=1)
    table_frame.rowconfigure(0, weight=1)

    self.history_tree = ttk.Treeview(table_frame, columns=HISTORY_TREE_COLUMNS, show="headings", selectmode="browse", style="Costing.Treeview")
    column_widths = {
        "changed_at": 150,
        "scope_label": 120,
        "entity_label": 180,
        "action_label": 100,
        "user_display_name": 150,
        "summary": 580,
    }
    for column_key in HISTORY_TREE_COLUMNS:
        anchor = "w"
        if column_key == "changed_at":
            anchor = "center"
        self.history_tree.column(column_key, width=column_widths[column_key], anchor=anchor, stretch=column_key == "summary")
        self.history_tree.heading(column_key, text=self.t(f"history_column_{column_key}"))

    scroll_y = ttk.Scrollbar(table_frame, orient="vertical", command=self.history_tree.yview)
    scroll_x = ttk.Scrollbar(table_frame, orient="horizontal", command=self.history_tree.xview)
    self.history_tree.configure(yscrollcommand=scroll_y.set, xscrollcommand=scroll_x.set)
    self.history_tree.grid(row=0, column=0, sticky="nsew")
    scroll_y.grid(row=0, column=1, sticky="ns")
    scroll_x.grid(row=1, column=0, sticky="ew")

    self.history_status_label = ttk.Label(
        parent,
        textvariable=self.status_var,
        relief="sunken",
        anchor="w",
        justify="left",
        padding=8,
        wraplength=1180,
    )
    self.history_status_label.grid(row=3, column=0, sticky="ew", pady=(12, 0))


def translate_history_scope(self, scope_key: str) -> str:
    scope = str(scope_key or "").strip()
    if not scope or scope == "__all__":
        return self.t("history_filter_all_modules")
    return self.t(f"menu_{scope}")


def refresh_history_module(self) -> None:
    self.history_rows = self.load_entity_history_rows_from_source()
    self.apply_history_filter()


def commit_history_search_filters(self, *, apply_filter: bool = True) -> None:
    self.history_user_committed_value = self.history_user_var.get().strip()
    self.history_keyword_committed_value = self.history_keyword_var.get().strip()
    if apply_filter:
        self.apply_history_filter()


def on_history_search_submit(self, _event: object | None = None) -> str:
    self.commit_history_search_filters()
    return "break"


def apply_history_filter(self) -> None:
    rows = list(getattr(self, "history_rows", []) or [])
    scope_filter_label = self.history_scope_var.get().strip()
    scope_filter = dict(getattr(self, "history_scope_options_by_label", {})).get(scope_filter_label, "__all__")
    user_filter = str(getattr(self, "history_user_committed_value", self.history_user_var.get()) or "").strip().lower()
    keyword = str(getattr(self, "history_keyword_committed_value", self.history_keyword_var.get()) or "").strip().lower()
    from_text = self.history_date_from_var.get().strip()
    to_text = self.history_date_to_var.get().strip()

    filtered: list[dict] = []
    for row in rows:
        if scope_filter and scope_filter != "__all__" and str(row.get("scope", "")).strip() != scope_filter:
            continue
        if user_filter:
            user_haystack = " ".join(
                [
                    str(row.get("user_display_name", "")).strip(),
                    str(row.get("user_email", "")).strip(),
                ]
            ).lower()
            if user_filter not in user_haystack:
                continue
        if keyword:
            haystack = " ".join(
                [
                    str(row.get("entity_label", "")).strip(),
                    str(row.get("summary", "")).strip(),
                    " | ".join(str(item).strip() for item in list(row.get("details", [])) if str(item).strip()),
                ]
            ).lower()
            if keyword not in haystack:
                continue
        if not self.is_within_date_range(row.get("changed_at"), from_text, to_text):
            continue
        filtered.append(row)

    self.filtered_history_rows = filtered
    self.refresh_history_tree()


def refresh_history_tree(self) -> None:
    if not hasattr(self, "history_tree"):
        return
    for item_id in self.history_tree.get_children():
        self.history_tree.delete(item_id)

    for index, row in enumerate(self.filtered_history_rows, start=1):
        values = (
            self.display_value(row.get("changed_at")),
            self.display_value(row.get("scope_label")),
            self.display_value(row.get("entity_label")),
            self.display_value(row.get("action_label")),
            self.display_value(row.get("user_display_name")),
            self.display_value(row.get("summary")),
        )
        self.history_tree.insert("", "end", str(index), values=values, tags=("odd_row" if index % 2 == 1 else "even_row",))

    self.set_status(self.t("history_status_loaded", count=len(self.filtered_history_rows)))


def bind_history_module(app_cls) -> None:
    setattr(app_cls, "HISTORY_SCOPE_OPTIONS", HISTORY_SCOPE_OPTIONS)
    method_map = {
        "_build_history_module": _build_history_module,
        "translate_history_scope": translate_history_scope,
        "refresh_history_module": refresh_history_module,
        "commit_history_search_filters": commit_history_search_filters,
        "on_history_search_submit": on_history_search_submit,
        "apply_history_filter": apply_history_filter,
        "refresh_history_tree": refresh_history_tree,
    }
    for method_name, function in method_map.items():
        setattr(app_cls, method_name, function)
