"""
ui_helpers.py — Reusable UI components for HKD Desktop (PySide6)
Design system: 4/8/16/24px scale, 36px inputs/buttons, 6px radius
"""
from PySide6.QtWidgets import (
    QPushButton, QLineEdit, QComboBox, QLabel, QWidget,
    QHBoxLayout, QVBoxLayout, QFrame, QSizePolicy, QTableWidget,
    QHeaderView, QAbstractItemView, QGroupBox, QFormLayout, QTextEdit,
    QSpinBox, QDoubleSpinBox, QDateEdit
)
from PySide6.QtCore import Qt, QDate, QTimer, QPropertyAnimation, QEasingCurve, QPoint, QSize
from PySide6.QtGui import QFont, QIcon
import os as _os

from gui.theme import COLORS

# ── Spacing Scale ─────────────────────────────────────────────────────────────
SP = {"XS": 4, "S": 8, "M": 16, "L": 24, "XL": 32}

# Standard heights
H_INPUT  = 36    # Input field height
H_BTN    = 36    # Button height
H_BTN_SM = 30    # Small button (table row actions)
H_ROW    = 36    # Table row height

# Label column width in forms
LABEL_COL_W = 150


# ── Icons ───────────────────────────────────────────────────────────────────
_ASSETS = _os.path.join(_os.path.dirname(__file__), "assets")

def _load_icon(filename: str) -> QIcon:
    """Tải icon từ thư mục assets."""
    if not filename: return QIcon()
    path = _os.path.join(_ASSETS, filename)
    if _os.path.exists(path):
        return QIcon(path)
    return QIcon()


# ── Buttons ───────────────────────────────────────────────────────────────────

def _setup_button_icon(btn: QPushButton, icon):
    """Cài đặt icon cho nút (hỗ trợ cả emoji string và QIcon)."""
    if isinstance(icon, QIcon):
        if not icon.isNull():
            btn.setIcon(icon)
            btn.setIconSize(QSize(20, 20))
    elif isinstance(icon, str) and icon.strip():
        # Nếu là emoji hoặc text
        if btn.text():
            btn.setText(f"{icon}  {btn.text()}".strip())
        else:
            btn.setText(icon)

def PrimaryButton(text: str, icon=None) -> QPushButton:
    """Nút chính: Save, Submit, Thêm."""
    btn = QPushButton(text)
    btn.setObjectName("btn_primary")
    btn.setFixedHeight(H_BTN)
    btn.setMinimumWidth(96)
    btn.setCursor(Qt.CursorShape.PointingHandCursor)
    btn.setFont(QFont("Segoe UI", 10, QFont.Weight.DemiBold))
    if icon:
        _setup_button_icon(btn, icon)
    return btn


def SecondaryButton(text: str, icon=None) -> QPushButton:
    """Nút phụ: Cancel, Đóng, Quay lại."""
    btn = QPushButton(text)
    btn.setObjectName("btn_secondary")
    btn.setFixedHeight(H_BTN)
    btn.setMinimumWidth(80)
    btn.setCursor(Qt.CursorShape.PointingHandCursor)
    btn.setFont(QFont("Segoe UI", 10))
    if icon:
        _setup_button_icon(btn, icon)
    return btn


def DangerButton(text: str, icon=None) -> QPushButton:
    """Nút nguy hiểm: Xóa, Reset."""
    btn = QPushButton(text)
    btn.setObjectName("btn_danger")
    btn.setFixedHeight(H_BTN)
    btn.setMinimumWidth(80)
    btn.setCursor(Qt.CursorShape.PointingHandCursor)
    btn.setFont(QFont("Segoe UI", 10, QFont.Weight.DemiBold))
    if icon:
        _setup_button_icon(btn, icon)
    return btn


def GhostButton(text: str, icon=None) -> QPushButton:
    """Nút nhỏ gọn: Export, Filter."""
    btn = QPushButton(text)
    btn.setObjectName("btn_ghost")
    btn.setFixedHeight(H_BTN_SM)
    btn.setMinimumWidth(72)
    btn.setCursor(Qt.CursorShape.PointingHandCursor)
    btn.setFont(QFont("Segoe UI", 9))
    if icon:
        _setup_button_icon(btn, icon)
    return btn


def IconButton(icon, tooltip: str = "") -> QPushButton:
    """Nút icon-only cho table actions."""
    btn = QPushButton()
    if isinstance(icon, QIcon):
        btn.setIcon(icon)
        btn.setIconSize(QSize(20, 20))
    else:
        btn.setText(str(icon))
        
    btn.setObjectName("btn_icon")
    btn.setFixedSize(30, 30)
    btn.setCursor(Qt.CursorShape.PointingHandCursor)
    if tooltip:
        btn.setToolTip(tooltip)
    return btn


# ── Form Action Bar ────────────────────────────────────────────────────────────

class FormActionsBar(QWidget):
    """
    Thanh actions chuẩn ở cuối form.
    Luôn align right: [Cancel] [Primary]
    """
    def __init__(self, primary_text="Lưu", cancel_text="Hủy", danger_text="", parent=None):
        super().__init__(parent)
        layout = QHBoxLayout(self)
        layout.setContentsMargins(0, SP["S"], 0, 0)
        layout.setSpacing(SP["S"])

        layout.addStretch()

        if danger_text:
            self.btn_danger = DangerButton(danger_text)
            layout.addWidget(self.btn_danger)
        else:
            self.btn_danger = None

        if cancel_text:
            self.btn_cancel = SecondaryButton(cancel_text)
            layout.addWidget(self.btn_cancel)
        else:
            self.btn_cancel = None

        self.btn_primary = PrimaryButton(primary_text)
        layout.addWidget(self.btn_primary)


# ── Input Helpers ──────────────────────────────────────────────────────────────

def make_input(placeholder: str = "", read_only: bool = False) -> QLineEdit:
    """QLineEdit chuẩn hóa."""
    inp = QLineEdit()
    inp.setFixedHeight(H_INPUT)
    inp.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
    if placeholder:
        inp.setPlaceholderText(placeholder)
    if read_only:
        inp.setReadOnly(True)
        inp.setObjectName("input_readonly")
    return inp


def make_combo(items: list = None) -> QComboBox:
    """QComboBox chuẩn hóa."""
    combo = QComboBox()
    combo.setFixedHeight(H_INPUT)
    combo.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
    combo.setFont(QFont("Segoe UI", 10))
    if items:
        combo.addItems(items)
    return combo


def make_date_edit(default_today: bool = True) -> QDateEdit:
    """QDateEdit chuẩn hóa."""
    de = QDateEdit()
    de.setFixedHeight(H_INPUT)
    de.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
    de.setCalendarPopup(True)
    de.setDisplayFormat("dd/MM/yyyy")
    if default_today:
        de.setDate(QDate.currentDate())
    return de


def make_spinbox(min_val=0, max_val=999_999_999, prefix="", suffix="") -> QDoubleSpinBox:
    """QDoubleSpinBox chuẩn hóa."""
    sb = QDoubleSpinBox()
    sb.setFixedHeight(H_INPUT)
    sb.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
    sb.setRange(min_val, max_val)
    sb.setGroupSeparatorShown(True)
    sb.setDecimals(0)
    if prefix:
        sb.setPrefix(prefix)
    if suffix:
        sb.setSuffix(suffix)
    return sb


def mark_error(widget: QWidget, has_error: bool = True) -> None:
    """Đánh dấu input lỗi bằng border đỏ."""
    widget.setProperty("error", "true" if has_error else "false")
    widget.style().unpolish(widget)
    widget.style().polish(widget)


# ── Search Bar ────────────────────────────────────────────────────────────────

def make_search_bar(placeholder: str = "🔍  Tìm kiếm...") -> QLineEdit:
    """Thanh tìm kiếm chuẩn."""
    search = QLineEdit()
    search.setFixedHeight(H_INPUT)
    search.setPlaceholderText(placeholder)
    search.setObjectName("search_bar")
    search.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
    return search


class FilterBar(QWidget):
    """
    Thanh lọc/tìm kiếm phía trên table.
    Hỗ trợ cả khởi tạo bằng widgets hoặc dùng các phương thức add_*.
    """
    def __init__(self, *widgets, parent=None):
        super().__init__(parent)
        self.layout = QHBoxLayout(self)
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.layout.setSpacing(SP["S"])
        
        for i, w in enumerate(widgets):
            stretch = 1 if i == 0 else 0
            self.layout.addWidget(w, stretch=stretch)

    def add_search(self, placeholder: str = "🔍  Tìm kiếm...") -> QLineEdit:
        """Thêm thanh tìm kiếm vào đầu bar."""
        search = make_search_bar(placeholder)
        self.layout.insertWidget(0, search, stretch=1)
        return search

    def add_date_range(self):
        """Thêm bộ chọn khoảng ngày (Từ ngày - Đến ngày)."""
        container = QWidget()
        l = QHBoxLayout(container)
        l.setContentsMargins(0, 0, 0, 0)
        l.setSpacing(SP["S"])
        
        l.addWidget(QLabel("Từ:"))
        de_from = make_date_edit()
        de_from.setFixedWidth(120)
        l.addWidget(de_from)
        
        l.addWidget(QLabel("đến"))
        de_to = make_date_edit()
        de_to.setFixedWidth(120)
        l.addWidget(de_to)
        
        self.layout.addWidget(container)
        return de_from, de_to


# ── Table Helper ──────────────────────────────────────────────────────────────

def apply_table_style(table: QTableWidget,
                      stretch_col: int = 1,
                      fixed_cols: dict = None) -> None:
    """
    Áp dụng chuẩn styling cho QTableWidget.
    fixed_cols = {col_index: width_px, ...}
    """
    table.setAlternatingRowColors(True)
    table.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
    table.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers)
    table.setShowGrid(False)
    table.verticalHeader().setVisible(False)
    table.verticalHeader().setDefaultSectionSize(H_ROW)
    table.horizontalHeader().setHighlightSections(False)
    table.horizontalHeader().setDefaultAlignment(
        Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter
    )
    header = table.horizontalHeader()
    header.setSectionResizeMode(stretch_col, QHeaderView.ResizeMode.Stretch)
    if fixed_cols:
        for col, w in fixed_cols.items():
            header.setSectionResizeMode(col, QHeaderView.ResizeMode.Fixed)
            table.setColumnWidth(col, w)
    table.setFrameShape(QFrame.Shape.NoFrame)


def right_align_cell(table: QTableWidget, row: int, col: int) -> None:
    """Căn phải 1 ô (dùng cho cột số tiền)."""
    item = table.item(row, col)
    if item:
        item.setTextAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)


# ── Section Label & Separator ─────────────────────────────────────────────────

def SectionTitle(text: str) -> QLabel:
    """Tiêu đề section trong form/page."""
    lbl = QLabel(text)
    lbl.setFont(QFont("Segoe UI", 11, QFont.Weight.DemiBold))
    lbl.setStyleSheet(f"color: {COLORS['text_primary']}; padding-bottom: 4px;")
    return lbl


def HSeparator() -> QFrame:
    """Đường kẻ ngang phân cách section."""
    line = QFrame()
    line.setFrameShape(QFrame.Shape.HLine)
    line.setFixedHeight(1)
    line.setStyleSheet(f"background-color: {COLORS['border']}; border: none;")
    return line


# ── Form Builder Helper ───────────────────────────────────────────────────────

def make_form(label_width: int = LABEL_COL_W) -> QFormLayout:
    """QFormLayout chuẩn hóa."""
    form = QFormLayout()
    form.setSpacing(SP["S"])
    form.setContentsMargins(0, 0, 0, 0)
    form.setLabelAlignment(
        Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter
    )
    form.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow)
    return form


def make_group(title: str, content_layout=None) -> QGroupBox:
    """QGroupBox chuẩn hóa với margins. Layout luôn được tạo sẵn."""
    group = QGroupBox(title)
    group.setFont(QFont("Segoe UI", 10, QFont.Weight.DemiBold))
    inner = QVBoxLayout(group)          # ← luôn tạo layout
    inner.setContentsMargins(SP["M"], SP["L"], SP["M"], SP["M"])
    inner.setSpacing(SP["S"])
    if content_layout:
        inner.addLayout(content_layout)
    return group


# ── Page Header ───────────────────────────────────────────────────────────────

def PageHeader(title: str, subtitle: str = "") -> QWidget:
    """Header chuẩn phía đầu màn hình."""
    header = QWidget()
    header.setObjectName("page_header")
    header.setFixedHeight(64)
    layout = QVBoxLayout(header)
    layout.setContentsMargins(SP["L"], SP["S"], SP["L"], SP["S"])
    layout.setSpacing(2)

    t = QLabel(title)
    t.setObjectName("page_title")
    t.setFont(QFont("Segoe UI", 15, QFont.Weight.Bold))
    layout.addWidget(t)

    if subtitle:
        s = QLabel(subtitle)
        s.setObjectName("page_subtitle")
        s.setFont(QFont("Segoe UI", 9))
        s.setStyleSheet(f"color: {COLORS['text_muted']};")
        layout.addWidget(s)

    return header


# ── Card Frame ────────────────────────────────────────────────────────────────

def CardFrame() -> QFrame:
    """QFrame card chuẩn."""
    card = QFrame()
    card.setObjectName("card")
    card.setFrameShape(QFrame.Shape.StyledPanel)
    return card


# ── Centered Form Container ───────────────────────────────────────────────────

def make_centered_container(inner: QWidget, max_width: int = 1000) -> QWidget:
    """
    Bọc widget trong container có stretch hai bên.
    Form không bị kéo full width trên màn 1920px.

    Dùng cho các trang form đơn (không phải bảng).
    """
    wrapper = QWidget()
    h = QHBoxLayout(wrapper)
    h.setContentsMargins(0, 0, 0, 0)
    h.setSpacing(0)
    h.addStretch(1)
    inner.setMaximumWidth(max_width)
    inner.setSizePolicy(
        QSizePolicy.Policy.Preferred,
        QSizePolicy.Policy.Expanding,
    )
    h.addWidget(inner, stretch=0)
    h.addStretch(1)
    return wrapper


# ── Toast Notification ────────────────────────────────────────────────────────

class ToastNotification(QFrame):
    """
    Thông báo popup không chặn (non-blocking) ở góc dưới bên phải.
    Có các mức độ: success (xanh), warning (vàng), error (đỏ).
    """
    def __init__(self, parent, message: str, type: str = "success", msec: int = 3000):
        super().__init__(parent)
        self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.ToolTip)
        self.setObjectName("toast_notification")
        
        # Colors mapping
        colors = {
            "success": ("#FFFFFF", "#27AE60", "#2C3E50"), # Nền trắng, viền xanh lá, chữ tối
            "info":    ("#FFFFFF", "#2980B9", "#2C3E50"), # Nền trắng, viền xanh dương, chữ tối
            "warning": ("#FFFFFF", "#F1C40F", "#2C3E50"), # Nền trắng, viền vàng, chữ tối
            "error":   ("#FFFFFF", "#E74C3C", "#2C3E50"), # Nền trắng, viền đỏ, chữ tối
        }
        bg, border, text = colors.get(type, colors["success"])

        # Layout
        layout = QHBoxLayout(self)
        layout.setContentsMargins(15, 6, 15, 6)
        
        self.lbl = QLabel(message)
        self.lbl.setWordWrap(True)
        self.lbl.setAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
        self.lbl.setFont(QFont("Segoe UI", 9, QFont.Weight.Medium)) # Hơi nhỏ font đi 1 chút
        self.lbl.setStyleSheet(f"color: {text}; border: none; background: transparent;")
        
        layout.addWidget(self.lbl)
        
        # Style (White background, colored border)
        self.setStyleSheet(f"""
            #toast_notification {{
                background-color: {bg};
                border: 2px solid {border};
                border-radius: 8px;
            }}
        """)
        
        # Size logic
        self.setFixedWidth(320)
        self.adjustSize()
        
        self.parent_widget = parent
        self._reposition()

        # Timer
        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.timeout.connect(self._fade_out)
        self.timer.start(msec)
        
        # Animation
        self.setWindowOpacity(0.0)
        self.anim_in = QPropertyAnimation(self, b"windowOpacity")
        self.anim_in.setDuration(300)
        self.anim_in.setStartValue(0.0)
        self.anim_in.setEndValue(1.0)
        self.anim_in.start()
        
        self.show()
        self.raise_()

    def _reposition(self):
        if self.parent_widget:
            p_pos = self.parent_widget.mapToGlobal(QPoint(0, 0))
            p_rect = self.parent_widget.rect()
            x = p_pos.x() + p_rect.width() - self.width() - 25
            y = p_pos.y() + p_rect.height() - self.height() - 25
            self.move(x, y)
        else:
            screen = self.screen().availableGeometry()
            x = screen.width() - self.width() - 25
            y = screen.height() - self.height() - 25
            self.move(x, y)

    def _fade_out(self):
        self.anim_out = QPropertyAnimation(self, b"windowOpacity")
        self.anim_out.setDuration(400)
        self.anim_out.setStartValue(self.windowOpacity())
        self.anim_out.setEndValue(0.0)
        self.anim_out.finished.connect(self.deleteLater)
        self.anim_out.start()

def show_toast(parent, message: str, type: str = "success", msec: int = 3000):
    """Helper để hiển thị toast nhanh."""
    return ToastNotification(parent, message, type, msec)
