"""
revenue_module.py — Module Sổ Tay Thu/Chi Hàng Ngày
Trang quản lý thu chi đơn giản cho Hộ Kinh Doanh nhỏ (Nhóm 1 & 2).

⚠️ TUYÊN BỐ MIỄN TRỪ TRÁCH NHIỆM:
Phần mềm chỉ hỗ trợ theo dõi và ước tính dòng tiền thực tế. Số liệu mang tính tham
khảo. Chủ hộ kinh doanh chịu trách nhiệm pháp lý về việc kê khai và nộp thuế
theo quy định hiện hành (Luật TNCN 109/2025/QH15 + Luật GTGT 48/2024/QH15).
"""
import os
import sys
from datetime import datetime, date
import json
import requests

from PySide6.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QLabel, QFrame,
    QLineEdit, QComboBox, QPushButton, QScrollArea,
    QGroupBox, QGridLayout, QMessageBox, QTableWidget,
    QTableWidgetItem, QHeaderView, QSizePolicy, QTabWidget,
    QDateEdit, QAbstractItemView, QProgressBar, QApplication,
    QDoubleSpinBox, QTextBrowser, QDialog, QTextEdit
)
from PySide6.QtCore import Qt, QDate, QTimer, QUrl
from PySide6.QtGui import QFont, QColor, QDoubleValidator, QDesktopServices

# make sure src/ is on path
_SRC = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
if _SRC not in sys.path:
    sys.path.insert(0, _SRC)

from gui.theme import COLORS
from gui.ui_helpers import (
    SP, PrimaryButton, SecondaryButton, DangerButton, GhostButton,
    make_input, make_combo, make_date_edit, make_form, make_group,
    CardFrame, apply_table_style, IconButton, FilterBar, PageHeader,
    show_toast, _load_icon
)

from core.revenue_db import (
    init_revenue_db, add_revenue, get_recent_entries,
    get_monthly_summary, get_daily_summary, get_yearly_summary,
    get_entries_by_month, delete_revenue, update_revenue, get_revenue_by_id,
    add_expense, get_expenses_by_month, delete_expense, get_expense_by_id, update_expense, get_recent_expenses,
    get_total_entry_count,
    CATEGORIES, CATEGORY_KEYS, CATEGORY_LABELS, REVENUE_THRESHOLD,
)
from core.inventory import get_stock_summary, add_movement


def _fmt_vnd(amount: float) -> str:
    """Format số tiền VND: 1,500,000 đ"""
    return f"{amount:,.0f} đ"


def _fmt_vnd_short(amount: float) -> str:
    """Format ngắn: 1.5M, 500tr, 1.2tỷ"""
    if amount >= 1_000_000_000:
        return f"{amount / 1_000_000_000:.2f} tỷ"
    if amount >= 1_000_000:
        return f"{amount / 1_000_000:.1f}tr"
    return f"{amount:,.0f}đ"


# ─────────────────────────────────────────────────────────────────────────────
# KPI Card
# ─────────────────────────────────────────────────────────────────────────────

class KpiCard(QFrame):
    """Thẻ KPI nhỏ hiển thị 1 chỉ số."""

    def __init__(self, title: str, value: str = "—", color: str = "", parent=None):
        super().__init__(parent)
        self.setObjectName("stat_card")
        self.setMinimumHeight(96)
        self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(16, 12, 16, 12)
        layout.setSpacing(2)

        self._title_lbl = QLabel(title)
        self._title_lbl.setObjectName("label_muted")
        self._title_lbl.setFont(QFont("Segoe UI", 9))

        self._value_lbl = QLabel(value)
        self._value_lbl.setFont(QFont("Segoe UI", 18, QFont.Weight.Bold))
        col = color or COLORS["text_primary"]
        self._value_lbl.setStyleSheet(f"color: {col}; background: transparent; border: none;")

        layout.addWidget(self._title_lbl)
        layout.addWidget(self._value_lbl)

    def set_value(self, value: str):
        self._value_lbl.setText(value)

    def set_color(self, color: str):
        self._value_lbl.setStyleSheet(f"color: {color}; background: transparent; border: none;")


# ─────────────────────────────────────────────────────────────────────────────
# Warning Banner
# ─────────────────────────────────────────────────────────────────────────────

class WarningBanner(QFrame):
    """Banner cảnh báo ngưỡng thuế (ẩn khi an toàn)."""

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setObjectName("card")
        self.setVisible(False)

        layout = QHBoxLayout(self)
        layout.setContentsMargins(18, 12, 18, 12)

        self._icon = QLabel("⚠️")
        self._icon.setFont(QFont("Segoe UI", 18))
        self._icon.setStyleSheet("background: transparent; border: none;")

        self._msg = QLabel()
        self._msg.setFont(QFont("Segoe UI", 10, QFont.Weight.Bold))
        self._msg.setWordWrap(True)
        self._msg.setStyleSheet("background: transparent; border: none;")

        layout.addWidget(self._icon)
        layout.addWidget(self._msg, stretch=1)

    def update_warning(self, level: str, pct: float, total: float):
        """Cập nhật nội dung và màu sắc banner."""
        if level == "safe":
            self.setVisible(False)
            return

        self.setVisible(True)
        remaining = max(0.0, REVENUE_THRESHOLD - total)

        if level == "danger":
            pix = _load_icon("baomat_128.png").pixmap(32, 32)
            self._icon.setPixmap(pix)
            self._msg.setText(
                f"ĐÃ VƯỢT ngưỡng miễn thuế 500 triệu! "
                f"Doanh thu hiện tại: {_fmt_vnd(total)} ({pct:.1f}%). "
                f"Bạn cần kê khai thuế GTGT và TNCN theo quy định 2026."
            )
            self._msg.setStyleSheet(f"color: {COLORS['danger']}; background: transparent; border: none;")
            self.setStyleSheet(
                f"QFrame#card {{ border: 2px solid {COLORS['danger']}; "
                f"background: {COLORS['danger_bg']}; border-radius: 10px; }}"
            )
        else:  # warning
            pix = _load_icon("baomat_128.png").pixmap(32, 32)
            self._icon.setPixmap(pix)
            self._msg.setText(
                f"Sắp đạt ngưỡng miễn thuế 500 triệu — hiện {pct:.1f}%! "
                f"Còn {_fmt_vnd(remaining)} trước khi phát sinh nghĩa vụ thuế. "
                f"Hãy chuẩn bị hồ sơ kê khai."
            )
            self._msg.setStyleSheet(f"color: {COLORS['warning']}; background: transparent; border: none;")
            self.setStyleSheet(
                f"QFrame#card {{ border: 2px solid {COLORS['warning']}; "
                f"background: {COLORS['warning_bg']}; border-radius: 10px; }}"
            )


# ─────────────────────────────────────────────────────────────────────────────
# Dialog: Phiếu Bán Hàng
# ─────────────────────────────────────────────────────────────────────────────

class SalesReceiptDialog(QDialog):
    """Hiển thị và in phiếu bán hàng dạng HTML."""

    def __init__(self, rows: list, total: float, entry_date: str,
                 customer: str, note: str, parent=None):
        super().__init__(parent)
        self.setWindowTitle("🛒 Phiếu bán hàng")
        self.setMinimumWidth(500)
        self.setStyleSheet("QLabel { background: transparent; }")
        self.setMinimumSize(580, 620)

        layout = QVBoxLayout(self)
        layout.setSpacing(12)

        self.browser = QTextBrowser()
        self.browser.setHtml(self._build_html(rows, total, entry_date, customer, note))
        layout.addWidget(self.browser)

        btn_row = QHBoxLayout()
        btn_print = PrimaryButton("In Phiếu", icon=_load_icon("action_print_128.png"))
        btn_print.clicked.connect(self._on_print)
        btn_close = SecondaryButton("Đóng")
        btn_close.clicked.connect(self.accept)
        btn_row.addStretch()
        btn_row.addWidget(btn_print)
        btn_row.addWidget(btn_close)
        layout.addLayout(btn_row)

    def _build_html(self, rows, total, entry_date, customer, note) -> str:
        items_html = ""
        for i, rd in enumerate(rows):
            items_html += f"""
            <tr style="background:{'#f9fafb' if i % 2 == 0 else '#ffffff'}">
                <td align="center">{i+1}</td>
                <td>{rd.get('name','')}</td>
                <td align="center">{rd.get('unit','')}</td>
                <td align="right">{float(rd.get('sl',0)):g}</td>
                <td align="right">{float(rd.get('price',0)):,.0f}</td>
                <td align="right"><b>{float(rd.get('total',0)):,.0f}</b></td>
            </tr>"""

        customer_line = f"Khách hàng: <b>{customer}</b>" if customer else "Khách lẻ"
        note_line = f"<p style='color:#555'>📝 {note}</p>" if note else ""
        return f"""<!DOCTYPE html><html><body style="font-family:Arial,sans-serif;font-size:13px;margin:24px">
        <div style="text-align:center;border-bottom:2px solid #2563eb;padding-bottom:12px;margin-bottom:16px">
            <h2 style="color:#2563eb;margin:0">PHIẾU BÁN HÀNG</h2>
            <p style="margin:4px 0;color:#555">Ngày: <b>{entry_date}</b> &nbsp;|&nbsp; {customer_line}</p>
            {note_line}
        </div>
        <table width="100%" border="1" cellspacing="0" cellpadding="7"
               style="border-collapse:collapse;border-color:#e5e7eb;font-size:13px">
            <thead>
                <tr style="background:#dbeafe;color:#1e40af;font-weight:bold">
                    <th width="40">STT</th>
                    <th>Tên hàng hóa / dịch vụ</th>
                    <th width="55">ĐVT</th>
                    <th width="65">SL</th>
                    <th width="110">Đơn giá</th>
                    <th width="120">Thành tiền</th>
                </tr>
            </thead>
            <tbody>{items_html}</tbody>
        </table>
        <div style="text-align:right;margin-top:14px;padding:10px;
                    background:#f0fdf4;border-radius:8px;border:1px solid #bbf7d0">
            <span style="font-size:16px;font-weight:bold;color:#16a34a">
                TỔNG CỘNG: {total:,.0f} đ
            </span>
        </div>
        <p style="text-align:center;color:#9ca3af;font-size:11px;margin-top:20px">
            Cảm ơn quý khách! — Phần mềm Quản lý HKD © 2026
        </p></body></html>"""

    def _on_print(self):
        try:
            from PySide6.QtPrintSupport import QPrinter, QPrintDialog
            printer = QPrinter(QPrinter.PrinterMode.HighResolution)
            dlg = QPrintDialog(printer, self)
            if dlg.exec():
                self.browser.print(printer)
        except Exception as e:
            QMessageBox.warning(self, "Lỗi in", f"Không thể in: {e}")


class ContractPickerDialog(QDialog):
    """Popup chọn hợp đồng bán/mua để điền nhanh vào form thu/chi."""

    def __init__(self, category: str, parent=None):
        super().__init__(parent)
        self.category = category
        self.selected_contract: dict | None = None
        self._rows: list[dict] = []
        self._visible_rows: list[dict] = []

        title = "Chọn Hợp Đồng Bán Hàng" if category == "sale" else "Chọn Hợp Đồng Mua Hàng"
        self.setWindowTitle(title)
        self.setMinimumSize(860, 460)

        layout = QVBoxLayout(self)
        layout.setSpacing(10)

        search_row = QHBoxLayout()
        self.inp_search = make_input("Tìm theo mã HĐ, tên hợp đồng, đối tác, MST...")
        self.inp_search.textChanged.connect(self._filter)
        search_row.addWidget(QLabel("🔍"))
        search_row.addWidget(self.inp_search)
        layout.addLayout(search_row)

        self.table = QTableWidget(0, 7)
        self.table.setHorizontalHeaderLabels(["Mã HĐ", "Tên HĐ", "Đối tác", "MST", "Ngày", "Số tiền", "Ghi chú"])
        self.table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
        self.table.setSelectionMode(QTableWidget.SelectionMode.SingleSelection)
        self.table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)
        self.table.setAlternatingRowColors(True)
        self.table.verticalHeader().setVisible(False)
        self.table.doubleClicked.connect(self._on_select)

        header = self.table.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch)
        header.setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch)
        header.setSectionResizeMode(3, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(4, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(5, QHeaderView.ResizeMode.ResizeToContents)
        header.setSectionResizeMode(6, QHeaderView.ResizeMode.Stretch)
        layout.addWidget(self.table)

        btn_row = QHBoxLayout()
        btn_row.addStretch()
        btn_cancel = GhostButton("Hủy")
        btn_cancel.clicked.connect(self.reject)
        btn_select = PrimaryButton("Nhập HĐ")
        btn_select.clicked.connect(self._on_select)
        btn_row.addWidget(btn_cancel)
        btn_row.addWidget(btn_select)
        layout.addLayout(btn_row)

        self._load_data()

    def _load_data(self):
        try:
            from core.contracts_db import init_db, get_all

            init_db()
            table = "contracts_sale" if self.category == "sale" else "contracts_purchase"
            self._rows = get_all(table)
        except Exception as e:
            self._rows = []
            QMessageBox.warning(self, "Lỗi", f"Không tải được danh sách hợp đồng: {e}")
        self._render(self._rows)

    def _partner_name(self, row: dict) -> str:
        if self.category == "sale":
            return (row.get("party_a") or row.get("party_b") or "").strip()
        return (row.get("party_b") or row.get("party_a") or "").strip()

    def _partner_tax(self, row: dict) -> str:
        if self.category == "sale":
            return (row.get("mst_a") or row.get("mst_b") or "").strip()
        return (row.get("mst_b") or row.get("mst_a") or "").strip()

    def _render(self, rows: list[dict]):
        self._visible_rows = list(rows)
        self.table.setRowCount(0)
        for row_data in rows:
            row = self.table.rowCount()
            self.table.insertRow(row)
            amount_item = QTableWidgetItem(_fmt_vnd(float(row_data.get("amount_total") or 0)))
            amount_item.setTextAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
            self.table.setItem(row, 0, QTableWidgetItem(row_data.get("name_file") or ""))
            self.table.setItem(row, 1, QTableWidgetItem(row_data.get("name") or ""))
            self.table.setItem(row, 2, QTableWidgetItem(self._partner_name(row_data)))
            self.table.setItem(row, 3, QTableWidgetItem(self._partner_tax(row_data)))
            self.table.setItem(row, 4, QTableWidgetItem(row_data.get("date") or ""))
            self.table.setItem(row, 5, amount_item)
            self.table.setItem(row, 6, QTableWidgetItem(row_data.get("note") or ""))

    def _filter(self, text: str):
        keyword = text.strip().lower()
        if not keyword:
            self._render(self._rows)
            return

        filtered = []
        for row in self._rows:
            haystack = " ".join([
                row.get("name_file") or "",
                row.get("name") or "",
                row.get("party_a") or "",
                row.get("party_b") or "",
                row.get("mst_a") or "",
                row.get("mst_b") or "",
                str(row.get("amount_total") or ""),
                row.get("note") or "",
            ]).lower()
            if keyword in haystack:
                filtered.append(row)

        self._render(filtered)

    def _on_select(self):
        row = self.table.currentRow()
        if row < 0 or row >= len(self._visible_rows):
            return
        self.selected_contract = self._visible_rows[row]
        self.accept()



# ─────────────────────────────────────────────────────────────────────────────
# Tab 1 — Nhập nhanh
# ─────────────────────────────────────────────────────────────────────────────

class QuickEntryTab(QWidget):
    """Tab nhập thu/chi nhanh."""

    def __init__(self, on_saved_callback, parent=None):
        super().__init__(parent)
        self._on_saved = on_saved_callback
        self._db_path: str = ""
        self._build_ui()

    def _build_ui(self):
        outer = QVBoxLayout(self)
        outer.setContentsMargins(0, 0, 0, 0)
        outer.setSpacing(0)

        # Lấy danh sách category cho từng loại
        income_cats  = [(k, v) for k, v in zip(CATEGORY_KEYS, CATEGORY_LABELS) if k.startswith("thu_") or k == "khac"]
        expense_cats = [(k, v) for k, v in zip(CATEGORY_KEYS, CATEGORY_LABELS) if k.startswith("chi_") or k == "khac"]
        self._income_keys  = [c[0] for c in income_cats]
        self._expense_keys = [c[0] for c in expense_cats]

        # Init Partner Cache
        self._company_db_path = ""
        self._partners_cache = []
        try:
            from core.company_manager import _get_default_db_path
            self._company_db_path = _get_default_db_path() or ""
        except Exception:
            pass

        from PySide6.QtWidgets import QCompleter
        from PySide6.QtCore import Qt
        
        self._completer_thu = QCompleter()
        self._completer_thu.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
        self._completer_thu.setFilterMode(Qt.MatchFlag.MatchContains)
        self._completer_thu.activated.connect(self._on_client_selected_thu)
        
        self._completer_chi = QCompleter()
        self._completer_chi.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
        self._completer_chi.setFilterMode(Qt.MatchFlag.MatchContains)
        self._completer_chi.activated.connect(self._on_client_selected_chi)

        self._load_partners_cache()

        # ── Sub-tab widget ────────────────────────────────────
        self._sub_tabs = QTabWidget()
        self._sub_tabs.setObjectName("entry_sub_tabs")

        # ── TAB 1: NHẬP THU (form đơn giản) ──────────────────
        tab_thu = QWidget()
        tab_thu_layout = QVBoxLayout(tab_thu)
        tab_thu_layout.setContentsMargins(0, 0, 0, 0)

        scroll_thu = QScrollArea()
        scroll_thu.setWidgetResizable(True)
        scroll_thu.setFrameShape(QFrame.Shape.NoFrame)

        body_thu = QWidget()
        bl_thu = QVBoxLayout(body_thu)
        bl_thu.setContentsMargins(35, 30, 35, 30)
        bl_thu.setSpacing(20)

        form_thu = make_form()

        layout_date_thu = QHBoxLayout()
        layout_date_thu.setContentsMargins(0, 0, 0, 0)
        self.date_thu = make_date_edit(default_today=True)
        btn_today_thu = SecondaryButton("Hôm nay")
        btn_today_thu.clicked.connect(lambda: self._set_today(self.date_thu))
        layout_date_thu.addWidget(self.date_thu, stretch=1)
        layout_date_thu.addWidget(btn_today_thu)

        self.amount_thu = make_input("0 đ")
        self.amount_thu.setFont(QFont("Segoe UI", 12))
        self.preview_thu = QLabel("0 đ")
        self.preview_thu.setFont(QFont("Segoe UI", 13, QFont.Weight.Bold))
        self.preview_thu.setStyleSheet(f"color: {COLORS['success']}; background: transparent; border: none;")

        self.cat_thu = make_combo([c[1] for c in income_cats])
        
        # Đối tác + Nút Chọn KH
        self.partner_thu = make_input("Nhập tên hoặc mã KH...")
        self.partner_thu.setCompleter(self._completer_thu)

        btn_pick_thu = SecondaryButton("👥 Chọn KH", icon=_load_icon("action_search_128.png"))
        btn_pick_thu.clicked.connect(lambda: self._on_pick_customer_dialog("thu"))
        
        layout_partner_thu = QHBoxLayout()
        layout_partner_thu.addWidget(self.partner_thu, stretch=1)
        layout_partner_thu.addWidget(btn_pick_thu)
        
        # --- Sản phẩm / Dịch vụ (Bỏ combo, dùng text để nhập cho dễ) ---
        self.prod_thu = make_input("Tên sản phẩm hoặc dịch vụ...")
        
        # Mã Hóa Đơn
        self.invoice_thu = make_input("Số hợp đồng/ Chứng từ ...")
        btn_contract_thu = SecondaryButton("Nhập HĐ", icon=_load_icon("action_import.ico"))
        btn_contract_thu.clicked.connect(lambda: self._on_pick_contract_dialog("thu"))

        layout_invoice_thu = QHBoxLayout()
        layout_invoice_thu.setContentsMargins(0, 0, 0, 0)
        layout_invoice_thu.addWidget(self.invoice_thu, stretch=1)
        layout_invoice_thu.addWidget(btn_contract_thu)

        # Ghi chú
        self.note_thu = self._make_standard_note("Chi tiết thêm (Vd: khách quen, giảm giá...)")

        self.btn_save_thu = PrimaryButton("  LƯU KHOẢN THU  ", icon="✅")
        self.btn_save_thu.setMinimumHeight(46)
        self.btn_save_thu.setStyleSheet(
            f"QPushButton {{ background-color: {COLORS['success']}; font-size: 14px; font-weight: bold; border-radius: 10px; }}"
            f"QPushButton:hover {{ background-color: #16a34a; }}"
        )
        self.btn_save_thu.clicked.connect(lambda: self._on_save_split("thu"))

        preview_thu_row = QHBoxLayout()
        preview_thu_row.addWidget(self.amount_thu, stretch=1)
        self.preview_thu.setMinimumWidth(120)
        self.preview_thu.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
        preview_thu_row.addWidget(self.preview_thu)

        form_thu.addRow(QLabel("Ngày:"),      layout_date_thu)
        form_thu.addRow(QLabel("Số tiền:"),   preview_thu_row)
        form_thu.addRow(QLabel("Phân loại:"), self.cat_thu)
        form_thu.addRow(QLabel("Đối tác:"),   layout_partner_thu)
        form_thu.addRow(QLabel("Mã HĐ:"),     layout_invoice_thu)
        form_thu.addRow(QLabel("Ghi chú:"),   self.note_thu)

        save_thu_row = QHBoxLayout()
        save_thu_row.addStretch()
        save_thu_row.addWidget(self.btn_save_thu)
        form_thu.addRow("", save_thu_row)

        bl_thu.addLayout(form_thu)
        bl_thu.addStretch()
        scroll_thu.setWidget(body_thu)
        tab_thu_layout.addWidget(scroll_thu)

        # ── TAB 2: CHI ────────────────────────────────────────
        tab_chi = QWidget()
        tab_chi_layout = QVBoxLayout(tab_chi)
        tab_chi_layout.setContentsMargins(0, 0, 0, 0)

        scroll_chi = QScrollArea()
        scroll_chi.setWidgetResizable(True)
        scroll_chi.setFrameShape(QFrame.Shape.NoFrame)

        body_chi = QWidget()
        bl_chi = QVBoxLayout(body_chi)
        bl_chi.setContentsMargins(35, 30, 35, 30)
        bl_chi.setSpacing(20)


        form_chi = make_form()

        layout_date_chi = QHBoxLayout()
        layout_date_chi.setContentsMargins(0, 0, 0, 0)
        self.date_chi = make_date_edit(default_today=True)
        btn_today_chi = SecondaryButton("Hôm nay")
        btn_today_chi.clicked.connect(lambda: self._set_today(self.date_chi))
        layout_date_chi.addWidget(self.date_chi, stretch=1)
        layout_date_chi.addWidget(btn_today_chi)

        self.amount_chi = make_input("0 đ")
        self.amount_chi.setFont(QFont("Segoe UI", 12))
        self.preview_chi = QLabel("0 đ")
        self.preview_chi.setFont(QFont("Segoe UI", 13, QFont.Weight.Bold))
        self.preview_chi.setStyleSheet(f"color: {COLORS['danger']}; background: transparent; border: none;")

        self.cat_chi = make_combo([c[1] for c in expense_cats])
        
        # Đối tác + Nút Chọn NCC
        self.partner_chi = make_input("Nhập tên hoặc mã KH/NCC...")
        self.partner_chi.setCompleter(self._completer_chi)

        btn_pick_chi = SecondaryButton("👥 Chọn KH/NCC", icon=_load_icon("action_search_128.png"))
        btn_pick_chi.clicked.connect(lambda: self._on_pick_customer_dialog("chi"))
        
        layout_partner_chi = QHBoxLayout()
        layout_partner_chi.addWidget(self.partner_chi, stretch=1)
        layout_partner_chi.addWidget(btn_pick_chi)
        
        # --- Sản phẩm / Dịch vụ (Bỏ combo, dùng text để nhập cho dễ) ---
        self.prod_chi = make_input("Tên sản phẩm hoặc dịch vụ...")
        
        # Mã Hóa Đơn
        self.invoice_chi = make_input("Số hợp đồng/ Chứng từ ...")
        btn_contract_chi = SecondaryButton("Nhập HĐ", icon=_load_icon("action_import.ico"))
        btn_contract_chi.clicked.connect(lambda: self._on_pick_contract_dialog("chi"))

        layout_invoice_chi = QHBoxLayout()
        layout_invoice_chi.setContentsMargins(0, 0, 0, 0)
        layout_invoice_chi.addWidget(self.invoice_chi, stretch=1)
        layout_invoice_chi.addWidget(btn_contract_chi)

        # Ghi chú
        self.note_chi = self._make_standard_note("Chi tiết thêm (Vd: tiền hàng, tiền điện...)")
 
        self.btn_save_chi = PrimaryButton("  LƯU KHOẢN CHI  ", icon="💸")
        self.btn_save_chi.setMinimumHeight(46)
        self.btn_save_chi.setStyleSheet(
            f"QPushButton {{ background-color: {COLORS['danger']}; font-size: 14px; font-weight: bold; border-radius: 10px; }}"
            f"QPushButton:hover {{ background-color: #b91c1c; }}"
        )
        self.btn_save_chi.clicked.connect(lambda: self._on_save_split("chi"))

        preview_chi_row = QHBoxLayout()
        preview_chi_row.addWidget(self.amount_chi, stretch=1)
        self.preview_chi.setMinimumWidth(120)
        self.preview_chi.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
        preview_chi_row.addWidget(self.preview_chi)

        form_chi.addRow(QLabel("Ngày:"),      layout_date_chi)
        form_chi.addRow(QLabel("Số tiền:"),   preview_chi_row)
        form_chi.addRow(QLabel("Phân loại:"), self.cat_chi)
        form_chi.addRow(QLabel("Đối tác:"),   layout_partner_chi)
        form_chi.addRow(QLabel("Mã HĐ:"),     layout_invoice_chi)
        form_chi.addRow(QLabel("Ghi chú:"),   self.note_chi)

        save_chi_row = QHBoxLayout()
        save_chi_row.addStretch()
        save_chi_row.addWidget(self.btn_save_chi)
        form_chi.addRow("", save_chi_row)

        # Ghi chú giải thích cho Nhóm 1
        lbl_info_chi = QLabel("ℹ️ Khoản chi không đưa vào Sổ S1a, chỉ dùng để tự quản lý lãi/lỗ nội bộ.")
        lbl_info_chi.setFont(QFont("Segoe UI", 9, QFont.Weight.Medium))
        lbl_info_chi.setStyleSheet("color: #64748b; font-style: italic;")
        lbl_info_chi.setAlignment(Qt.AlignmentFlag.AlignCenter)
        lbl_info_chi.setWordWrap(True)

        bl_chi.addLayout(form_chi)
        bl_chi.addWidget(lbl_info_chi)

        bl_chi.addStretch()

        scroll_chi.setWidget(body_chi)
        tab_chi_layout.addWidget(scroll_chi)

        # ── Thêm 2 tab vào sub-tab widget ────────────────────
        self._sub_tabs.addTab(tab_thu, "💰  NHẬP THU")
        self._sub_tabs.addTab(tab_chi, "📉  NHẬP CHI")

        outer.addWidget(self._sub_tabs)

        # Setup live preview
        self.amount_thu.textChanged.connect(lambda t: self._on_amt_changed_split(t, "thu"))
        self.amount_chi.textChanged.connect(lambda t: self._on_amt_changed_split(t, "chi"))

    def _make_standard_note(self, placeholder: str) -> QLineEdit:
        """Helper chung để tạo ô Ghi chú 1 dòng (Compact)."""
        return make_input(placeholder)



    def _set_today(self, date_edit: QDateEdit):
        now = datetime.now()
        date_edit.setDate(QDate(now.year, now.month, now.day))

    def _refresh_products(self):
        """Tải sản phẩm vào combo SP/DV."""
        main = self.window()
        db_path = getattr(main, "current_db_path", "")
        if not db_path:
            return
        try:
            items = get_stock_summary(db_path)
            # Cập nhật completer cho prod_thu & prod_chi (QLineEdit)
            from PySide6.QtWidgets import QCompleter
            completer_list = [f"{it['code']} - {it['name']}" for it in items]
            
            for field in [self.prod_thu, self.prod_chi]:
                completer = QCompleter(completer_list, field)
                completer.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
                completer.setFilterMode(Qt.MatchFlag.MatchContains)
                field.setCompleter(completer)
        except:
            pass

    # ── Database Partners Cache ─────────────────────────────────────
    def _load_partners_cache(self):
        """Nạp danh sách khách hàng từ DB vào completer."""
        db_path = getattr(self, '_company_db_path', '')
        if not db_path or not os.path.exists(db_path):
            return
        try:
            import sqlite3
            from PySide6.QtCore import QStringListModel
            conn = sqlite3.connect(db_path)
            conn.row_factory = sqlite3.Row
            rows = conn.execute(
                "SELECT code, name, tax_code, address, representative, position "
                "FROM partners WHERE is_active=1 ORDER BY name"
            ).fetchall()
            conn.close()
            self._partners_cache = [dict(r) for r in rows]
            # Tạo danh sách gợi ý
            suggestions = []
            for p in self._partners_cache:
                label = p.get('name', '')
                if p.get('code'):
                    label += f" [{p['code']}]"
                suggestions.append(label)
            model = QStringListModel(suggestions)
            self._completer_thu.setModel(model)
            self._completer_chi.setModel(model)
        except Exception as e:
            print(f"[QuickEntryTab] load partners error: {e}")

    def _on_client_selected_thu(self, text: str):
        self._handle_client_selected(text, "thu")

    def _on_client_selected_chi(self, text: str):
        self._handle_client_selected(text, "chi")

    def _handle_client_selected(self, text: str, kind: str):
        import re
        name_clean = re.sub(r'\s*\[.*?\]\s*$', '', text).strip()
        matched = next(
            (p for p in self._partners_cache
             if p.get('name', '').strip() == name_clean or
                (p.get('code') and f"[{p['code']}]" in text)),
            None
        )
        if not matched: return
        inp = self.partner_thu if kind == "thu" else self.partner_chi
        inp.setText(matched.get('name', ''))

    def _on_pick_customer_dialog(self, kind: str):
        """Mở popup chọn khách hàng."""
        db_path = getattr(self, '_company_db_path', '')
        if not db_path or not os.path.exists(db_path):
            try:
                from core.company_manager import _get_default_db_path
                db_path = _get_default_db_path() or ''
                self._company_db_path = db_path
            except Exception:
                pass
        if not db_path or not os.path.exists(db_path):
            from PySide6.QtWidgets import QMessageBox
            QMessageBox.warning(self, "Chưa có DB", "Chưa chọn công ty/database. Vào Cài Đặt để chọn.")
            return

        self._load_partners_cache()
        from gui.modules.customers_module import CustomerPickerDialog
        dlg = CustomerPickerDialog(db_path, parent=self)
        if kind == "thu":
            dlg.customer_selected.connect(self._fill_from_partner_thu)
        else:
            dlg.customer_selected.connect(self._fill_from_partner_chi)
        dlg.exec()

    def _fill_from_partner_thu(self, partner: dict):
        self.partner_thu.setText(partner.get('name', ''))
        
    def _fill_from_partner_chi(self, partner: dict):
        self.partner_chi.setText(partner.get('name', ''))

    def _on_pick_contract_dialog(self, kind: str):
        category = "sale" if kind == "thu" else "purchase"
        dlg = ContractPickerDialog(category=category, parent=self)
        if dlg.exec() and dlg.selected_contract:
            self._fill_from_contract(kind, dlg.selected_contract)

    def _set_default_contract_category(self, kind: str):
        if kind == "thu" and "thu_ban_hang" in self._income_keys:
            self.cat_thu.setCurrentIndex(self._income_keys.index("thu_ban_hang"))
        elif kind == "chi" and "chi_nhap_hang" in self._expense_keys:
            self.cat_chi.setCurrentIndex(self._expense_keys.index("chi_nhap_hang"))

    def _set_amount_from_contract(self, kind: str, amount_value):
        try:
            amount = float(amount_value or 0)
        except (TypeError, ValueError):
            amount = 0.0
        if amount <= 0:
            return

        target_input = self.amount_thu if kind == "thu" else self.amount_chi
        target_input.setText(f"{round(amount):,.0f}")

    def prefill_from_contract(self, kind: str, contract: dict):
        if kind not in ("thu", "chi"):
            return

        self._sub_tabs.setCurrentIndex(0 if kind == "thu" else 1)
        self._fill_from_contract(kind, contract)

        focus_input = self.amount_thu if kind == "thu" else self.amount_chi
        focus_input.setFocus()
        focus_input.selectAll()

    def _fill_from_contract(self, kind: str, contract: dict):
        is_income = kind == "thu"
        source_category = (contract.get("contract_category") or "").strip().lower()

        if source_category == "sale":
            partner = (contract.get("party_a") or contract.get("party_b") or "").strip()
        elif source_category == "purchase":
            partner = (contract.get("party_b") or contract.get("party_a") or "").strip()
        elif source_category == "other":
            partner = (
                contract.get("party_a") or contract.get("party_b") or ""
                if is_income
                else contract.get("party_b") or contract.get("party_a") or ""
            ).strip()
        else:
            partner = (
                contract.get("party_a") or contract.get("party_b") or ""
                if is_income
                else contract.get("party_b") or contract.get("party_a") or ""
            ).strip()

        contract_code = (contract.get("name_file") or contract.get("name") or "").strip()
        contract_name = (contract.get("name") or contract.get("note") or "").strip()
        contract_date = (contract.get("date") or "").strip()
        contract_amount = contract.get("amount_total")

        partner_input = self.partner_thu if is_income else self.partner_chi
        invoice_input = self.invoice_thu if is_income else self.invoice_chi
        note_input = self.note_thu if is_income else self.note_chi
        date_input = self.date_thu if is_income else self.date_chi

        if partner:
            partner_input.setText(partner)
        if contract_code:
            invoice_input.setText(contract_code)
        if contract_name and not note_input.text().strip():
            note_input.setText(contract_name)
        if contract_date:
            parsed = QDate.fromString(contract_date, "yyyy-MM-dd")
            if parsed.isValid():
                date_input.setDate(parsed)

        self._set_default_contract_category(kind)
        self._set_amount_from_contract(kind, contract_amount)



    def _on_amt_changed_split(self, text, kind):
        clean = text.replace(",", "").replace(".", "").replace(" ", "")
        label = self.preview_thu if kind == "thu" else self.preview_chi
        try:
            val = float(clean)
            label.setText(_fmt_vnd(val))
        except ValueError:
            label.setText("0 đ")

    def _on_save_split(self, kind):
        main = self.window()

        if not self._db_path or not os.path.exists(self._db_path):
            QMessageBox.warning(self, "Chưa có DB", "Chưa chọn công ty/database. Vào Cài Đặt để chọn.")
            return
        
        # 0. Check License Expiration & Limit (20 entries for expired trial)
        if hasattr(main, "is_expired") and main.is_expired:
            current_count = get_total_entry_count(self._db_path)
            if current_count >= 20: 
                QMessageBox.critical(self, "Bản quyền hết hạn", 
                    f"Bản quyền của bạn đã hết hạn và đạt giới hạn {current_count}/20 chứng từ dùng thử.\n"
                    "Vui lòng liên hệ hỗ trợ để gia hạn bản quyền bản PRO!")
                return
        
        if kind == "thu":
            date_edit, inp, cat_box, note_edit = self.date_thu, self.amount_thu, self.cat_thu, self.note_thu
            cat_keys = self._income_keys
            prod_combo = self.prod_thu
        else:
            date_edit, inp, cat_box, note_edit = self.date_chi, self.amount_chi, self.cat_chi, self.note_chi
            cat_keys = self._expense_keys
            prod_combo = self.prod_chi

        raw = inp.text().replace(",", "").replace(".", "").replace(" ", "")
        if not raw:
            QMessageBox.warning(self, "Thiếu thông tin", "Vui lòng nhập số tiền.")
            return

        try:
            amount = float(raw)
            if amount <= 0: raise ValueError("Số tiền phải lớn hơn 0")
            
            entry_date = date_edit.date().toString("yyyy-MM-dd")
            category = cat_keys[cat_box.currentIndex()] if 0 <= cat_box.currentIndex() < len(cat_keys) else "khac"

            if kind == "thu":
                partner_name = self.partner_thu.text().strip()
            else:
                partner_name = self.partner_chi.text().strip()

            # Set is_paid: Bán nợ (thu_no_cong) mặc định là 0 (chưa trả)
            is_paid = 0 if category == "thu_no_cong" else 1

            # Lưu vào Revenue DB
            p_code = None
            inv_code = None
            if kind == "thu":
                p_code = self.prod_thu.text().strip()
                inv_code = self.invoice_thu.text().strip()
                note = self.note_thu.text().strip()
            else:
                p_code = self.prod_chi.text().strip()
                inv_code = self.invoice_chi.text().strip()
                note = self.note_chi.text().strip()

            if kind == "thu":
                add_revenue(
                    amount=amount,
                    entry_date=entry_date,
                    category=category,
                    note=note,
                    product_code=p_code,
                    quantity=0, # Bỏ số lượng
                    partner_name=partner_name,
                    is_paid=is_paid,
                    invoice_code=inv_code,
                    db_path=self._db_path
                )
            else:
                add_expense(
                    amount=amount,
                    entry_date=entry_date,
                    category=category,
                    note=note,
                    product_code=p_code,
                    quantity=0,
                    partner_name=partner_name,
                    is_paid=is_paid,
                    invoice_code=inv_code,
                    db_path=self._db_path
                )

            # Reset form
            inp.clear()
            if kind == "thu":
                self.note_thu.clear()
                self.prod_thu.clear()
                self.invoice_thu.clear()
                self.partner_thu.clear()
            else:
                self.note_chi.clear()
                self.prod_chi.clear()
                self.invoice_chi.clear()
                self.partner_chi.clear()
            date_edit.setDate(QDate.currentDate())
            if self._on_saved: self._on_saved()

            if kind == "thu" and str(category).startswith("thu_tra_hang"):
                show_toast(
                    self.window(),
                    f"Đã lưu Trả hàng {_fmt_vnd(amount)} vào Lịch sử Doanh thu ({entry_date})"
                )
            else:
                show_toast(self.window(), f"Đã lưu khoản {'thu' if kind == 'thu' else 'chi'} {_fmt_vnd(amount)}")
        except ValueError as e:
            QMessageBox.warning(self, "Lỗi", str(e))
        except Exception as e:
            QMessageBox.critical(self, "❌ Lỗi", str(e))


# ─────────────────────────────────────────────────────────────────────────────
# Edit Dialog
# ─────────────────────────────────────────────────────────────────────────────

from PySide6.QtWidgets import QDialog, QDialogButtonBox

class EditEntryDialog(QDialog):
    def __init__(self, entry: dict, db_path: str, record_type: str = "thu", parent=None):
        super().__init__(parent)
        self.entry = entry
        self._db_path = db_path
        self._record_type = record_type
        self.setWindowTitle("✏️ Sửa giao dịch")
        self.setMinimumWidth(480)
        self.setStyleSheet("QLabel { background: transparent; }")
        
        # Main Layout
        self.main_layout = QVBoxLayout(self)
        self.main_layout.setSpacing(15)
        self.main_layout.setContentsMargins(25, 20, 25, 20)

        # Title
        title_lbl = QLabel(f"<b>ID Giao dịch: {entry['id']}</b>")
        title_lbl.setFont(QFont("Segoe UI", 11))
        self.main_layout.addWidget(title_lbl)
        
        # Form
        form_layout = make_form()
        
        # Tiền
        self.amount_edit = make_input()
        self.amount_edit.setText(str(int(entry["amount"])))
        self.amount_edit.setValidator(QDoubleValidator(0, 1000000000, 0))
        form_layout.addRow(QLabel("Số tiền:"), self.amount_edit)
        
        # Ngày
        self.date_edit = make_date_edit()
        try:
            self.date_edit.setDate(QDate.fromString(entry["entry_date"], "yyyy-MM-dd"))
        except:
            self.date_edit.setDate(QDate.currentDate())
        form_layout.addRow(QLabel("Ngày:"), self.date_edit)
        
        # Danh mục
        if self._record_type == "thu":
            valid_labels = [v for k, v in CATEGORIES.items() if k.startswith("thu_") or k == "khac"]
        else:
            valid_labels = [v for k, v in CATEGORIES.items() if k.startswith("chi_") or k == "khac"]
            
        self.cat_box = make_combo(valid_labels)
        current_label = entry.get("category_label", entry["category"])
        self.cat_box.setCurrentText(current_label)
        form_layout.addRow(QLabel("Phân loại:"), self.cat_box)

        # Đối tác
        self.partner_edit = make_input("Tên đối tác...")
        self.partner_edit.setText(entry.get("partner_name") or "")
        form_layout.addRow(QLabel("Đối tác:"), self.partner_edit)

        # Mã HĐ
        self.invoice_edit = make_input()
        self.invoice_edit.setText(entry.get("invoice_code") or "")
        form_layout.addRow(QLabel("Mã HĐ:"), self.invoice_edit)

        # Ghi chú (1 dòng)
        self.note_edit = make_input()
        self.note_edit.setText(entry.get("note") or "")
        form_layout.addRow(QLabel("Ghi chú:"), self.note_edit)

        self.main_layout.addLayout(form_layout)
        
        # Buttons
        self.button_box = QHBoxLayout()
        self.button_box.addStretch()
        
        cancel_btn = SecondaryButton("Hủy")
        cancel_btn.clicked.connect(self.reject)
        
        save_btn = PrimaryButton("Lưu thay đổi")
        save_btn.clicked.connect(self.accept)
        
        self.button_box.addWidget(cancel_btn)
        self.button_box.addWidget(save_btn)

        self.main_layout.addSpacing(10)
        self.main_layout.addLayout(self.button_box)

    def accept(self):
        if self._on_save():
            super().accept()

    def _on_save(self):
        try:
            amt = float(self.amount_edit.text() or 0)
            note = self.note_edit.text().strip()
            inv_code = self.invoice_edit.text().strip()
            # Category
            cat_label = self.cat_box.currentText()
            cat_key = "khac"
            for k, v in CATEGORIES.items():
                if v == cat_label:
                    cat_key = k
                    break
            
            d_str = self.date_edit.date().toString("yyyy-MM-dd")
            partner = self.partner_edit.text().strip()
            p_code = ""  # Đã bỏ field Sản phẩm khỏi UI

            # Determine is_paid based on new category
            # If user switches from thu_no_cong to a paid category, it's now paid.
            # If it's a return, we handle it too.
            new_is_paid = self.entry.get("is_paid", 1)
            if cat_key in ["thu_ban_hang", "thu_ban_hang_ck", "thu_tra_hang_tm", "thu_tra_hang_ck"]:
                new_is_paid = 1
            elif cat_key == "thu_no_cong":
                new_is_paid = 0

            # 3. Update DB
            if self._record_type == "chi":
                update_expense(
                    self.entry["id"], 
                    amount=amt, entry_date=d_str, category=cat_key, note=note,
                    invoice_code=inv_code, is_paid=new_is_paid,
                    partner_name=partner, product_code=p_code,
                    db_path=self._db_path
                )
            else:
                update_revenue(
                    self.entry["id"], 
                    amount=amt, entry_date=d_str, category=cat_key, note=note,
                    invoice_code=inv_code, is_paid=new_is_paid,
                    partner_name=partner, product_code=p_code,
                    db_path=self._db_path
                )
            return True
        except Exception as e:
            QMessageBox.critical(self, "Lỗi", str(e))
            return False

# ─────────────────────────────────────────────────────────────────────────────
# Tab 2 — Lịch sử
# ─────────────────────────────────────────────────────────────────────────────

class HistoryTab(QWidget):
    """Tab hiển thị lịch sử thu chi theo tháng."""

    def __init__(self, record_type="thu", on_deleted_callback=None, parent=None):
        super().__init__(parent)
        self._record_type = record_type
        self._on_deleted = on_deleted_callback
        self._db_path: str = ""
        self._build_ui()


    def _build_ui(self):
        layout = QVBoxLayout(self)
        layout.setContentsMargins(25, 20, 25, 20)
        layout.setSpacing(14)

        # ── Bộ lọc tháng ────────────────────────────────────
        filter_row = QHBoxLayout()
        filter_row.setSpacing(10)

        lbl_filter = QLabel("Xem tháng:")
        lbl_filter.setFont(QFont("Segoe UI", 10))

        now = datetime.now()
        # ✅ FIX: Thêm "Tất cả tháng" làm index 0, Tháng 1-12 là index 1-12
        months = ["Tất cả tháng"] + [f"Tháng {i}" for i in range(1, 13)]
        years  = [str(y) for y in range(2026, 2031)]  # Cố định 2026-2030

        self.combo_month = make_combo(months)
        # Mặc định xem tất cả tháng để tránh nhầm "đã lưu nhưng không thấy" khi chứng từ thuộc tháng khác.
        self.combo_month.setCurrentIndex(0)

        self.combo_year = make_combo(years)
        self.combo_year.setCurrentText(str(now.year))

        # Tự động tải dữ liệu khi thay đổi tháng/năm
        self.combo_month.currentIndexChanged.connect(self.refresh)
        self.combo_year.currentIndexChanged.connect(self.refresh)

        btn_load = SecondaryButton("Tải dữ liệu", icon="🔄")
        btn_load.clicked.connect(self.refresh)

        btn_sync = SecondaryButton("Đồng bộ Google Sheet", icon="📊")
        btn_sync.clicked.connect(self._on_sync_clicked)

        filter_row.addWidget(lbl_filter)
        filter_row.addWidget(self.combo_month)
        filter_row.addWidget(self.combo_year)
        filter_row.addSpacing(10)
        filter_row.addWidget(btn_load)
        filter_row.addWidget(btn_sync)
        filter_row.addStretch()

        self.lbl_total = QLabel("—")
        self.lbl_total.setFont(QFont("Segoe UI", 10, QFont.Weight.Bold))
        self.lbl_total.setStyleSheet(f"color: {COLORS['accent']}; background: #f0f7ff; padding: 10px; border-radius: 8px;")
        self.lbl_total.setWordWrap(True)
        
        layout.addWidget(self.lbl_total)
        layout.addLayout(filter_row)

        # ── Danh sách giao dịch dạng Bảng (Table) ────────────────
        self.table = QTableWidget(0, 7)
        self.table.setHorizontalHeaderLabels([
            "Ngày", "Phân loại", "Đối tác", "Ghi chú", "Mã HĐ", "Số tiền (Nợ)", "Thao tác"
        ])
        
        apply_table_style(self.table, stretch_col=-1)
        
        header = self.table.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.ResizeMode.Fixed)
        self.table.setColumnWidth(0, 100) # Ngày
        
        header.setSectionResizeMode(1, QHeaderView.ResizeMode.Fixed)
        self.table.setColumnWidth(1, 140) # Phân loại
        
        header.setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch) # Đối tác
        header.setSectionResizeMode(3, QHeaderView.ResizeMode.Stretch) # Sản phẩm - Ghi chú
        
        header.setSectionResizeMode(4, QHeaderView.ResizeMode.Fixed)
        self.table.setColumnWidth(4, 120) # Mã HĐ

        header.setSectionResizeMode(5, QHeaderView.ResizeMode.Fixed)
        self.table.setColumnWidth(5, 150) # Số tiền (Nợ)
        
        header.setSectionResizeMode(6, QHeaderView.ResizeMode.Fixed)
        self.table.setColumnWidth(6, 100) # Thao tác
        
        self.table.verticalHeader().setDefaultSectionSize(40)
        self.table.verticalHeader().setMinimumSectionSize(40)
        
        layout.addWidget(self.table)

        # Load initial data
        self.refresh()

    def refresh(self):
        """Tải lại dữ liệu theo bộ lọc hiện tại."""
        if not self._db_path or not os.path.exists(self._db_path):
            self.table.setRowCount(0)
            self.lbl_total.setText("Chưa chọn công ty/database.")
            return

        try:
            year = int(self.combo_year.currentText())
        except ValueError:
            year = datetime.now().year

        month_idx = self.combo_month.currentIndex()  # 0 = Tất cả, 1-12 = tháng

        if month_idx == 0:
            # Tất cả tháng trong năm đã chọn
            all_entries = []
            for m in range(1, 13):
                if self._record_type == "chi":
                    all_entries.extend(get_expenses_by_month(year, m, db_path=self._db_path))
                else:
                    all_entries.extend(get_entries_by_month(year, m, db_path=self._db_path))
            entries = all_entries
        else:
            if self._record_type == "chi":
                entries = get_expenses_by_month(year, month_idx, db_path=self._db_path)
            else:
                entries = get_entries_by_month(year, month_idx, db_path=self._db_path)

        # Lọc theo Loại (Thu/Chi)
        if self._record_type == "thu": # Khoản Thu
            entries = [
                e for e in entries
                if e.get("category", "").startswith("thu_")
                or e.get("category") in ["ban_hang", "dich_vu", "khac"]
            ]
        elif self._record_type == "chi": # Khoản Chi
            entries = [e for e in entries if e.get("category", "").startswith("chi_")]

        # Sắp xếp lại theo ngày mới nhất
        entries = sorted(entries, key=lambda e: e.get("entry_date", ""), reverse=True)

        self._populate_table(entries)

        # Update tổng Thu / Chi / Nợ dựa trên ngữ cảnh bộ lọc
        if self._record_type == "thu":
            total_thu = sum(
                e["amount"] if e["category"] in ("thu_ban_hang", "thu_ban_hang_ck", "thu_no_cong", "ban_hang", "dich_vu", "khac")
                else (-e["amount"] if str(e.get("category", "")).startswith("thu_tra_hang") else 0)
                for e in entries
            )
            total_no  = sum(e["amount"] for e in entries if e["category"] == "thu_no_cong" and e.get("is_paid") == 0)
            
            status_text = f"🟢 Tổng Doanh Thu (Thu): {_fmt_vnd(total_thu)}"
            if total_no > 0:
                status_text += f"   |   ⚠️ Nợ khách chưa trả: {_fmt_vnd_short(total_no)}"
                
        elif self._record_type == "chi":
            total_chi = sum(e["amount"] for e in entries if e["category"].startswith("chi_"))
            status_text = f"🔴 Tổng Chi Phí (Quản lý nội bộ): {_fmt_vnd(total_chi)}"
            
        self.lbl_total.setText(status_text)

    def _populate_table(self, entries: list[dict]):
        self.table.setRowCount(0)

        if not entries:
            return

        for row_idx, entry in enumerate(entries):
            self.table.insertRow(row_idx)

            # 1. Ngày
            try:
                dt = datetime.strptime(entry["entry_date"], "%Y-%m-%d")
                date_str = dt.strftime("%d/%m/%Y")
            except Exception:
                date_str = entry["entry_date"]
                
            item_date = QTableWidgetItem(date_str)
            item_date.setFont(QFont("Segoe UI", 10))
            self.table.setItem(row_idx, 0, item_date)

            # 2. Phân loại
            is_chi = entry["category"].startswith("chi_")
            is_return = str(entry.get("category", "")).startswith("thu_tra_hang")
            is_negative = is_chi or is_return
            cat_label = entry.get("category_label", entry["category"])

            item_cat = QTableWidgetItem(cat_label)
            item_cat.setFont(QFont("Segoe UI", 10, QFont.Weight.Bold))
            item_cat.setForeground(QColor(COLORS["danger"] if is_negative else COLORS["success"]))
            self.table.setItem(row_idx, 1, item_cat)
            
            # 3. Đối tác
            partner = entry.get("partner_name") or ""
            item_ptn = QTableWidgetItem(partner)
            item_ptn.setFont(QFont("Segoe UI", 10))
            self.table.setItem(row_idx, 2, item_ptn)

            # 4. Ghi chú
            note_str = entry.get("note", "") or ""
            item_sp = QTableWidgetItem(note_str)
            item_sp.setFont(QFont("Segoe UI", 9))
            item_sp.setForeground(QColor(COLORS["text_secondary"]))
            self.table.setItem(row_idx, 3, item_sp)

            # 5. Mã HĐ
            inv = entry.get("invoice_code") or ""
            item_inv = QTableWidgetItem(inv)
            item_inv.setFont(QFont("Consolas", 10))
            self.table.setItem(row_idx, 4, item_inv)

            # 6. Số tiền + Nợ
            amt_str = f"-{_fmt_vnd(entry['amount'])}" if is_negative else f"+{_fmt_vnd(entry['amount'])}"
            is_paid = entry.get("is_paid", 1)
            
            w_amt = QWidget()
            l_amt = QHBoxLayout(w_amt)
            l_amt.setContentsMargins(5, 0, 10, 0)
            l_amt.setSpacing(5)
            
            lbl_amt = QLabel(amt_str)
            lbl_amt.setFont(QFont("Segoe UI", 11, QFont.Weight.Bold))
            lbl_amt.setStyleSheet(f"color: {COLORS['danger'] if is_negative else COLORS['success']}; background: transparent;")
            lbl_amt.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
            
            l_amt.addStretch()
            if is_paid == 0:
                d_badge = QLabel("NỢ")
                d_badge.setFont(QFont("Segoe UI", 8, QFont.Weight.Bold))
                d_badge.setStyleSheet(f"background-color: {COLORS['warning']}; color: white; border-radius: 4px; padding: 2px 5px;")
                d_badge.setAlignment(Qt.AlignmentFlag.AlignCenter)
                l_amt.addWidget(d_badge)
            l_amt.addWidget(lbl_amt)
            
            self.table.setCellWidget(row_idx, 5, w_amt)

            # 7. Thao tác Sửa / Xóa
            w_act = QWidget()
            l_act = QHBoxLayout(w_act)
            l_act.setContentsMargins(5, 5, 5, 5)
            l_act.setSpacing(8)
            l_act.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft)
            
            btn_edit = IconButton(_load_icon("edit_128.png"), tooltip="Sửa bản ghi")
            btn_del = IconButton(_load_icon("action_cancel_128.png"), tooltip="Xóa bản ghi")
            
            btn_edit.clicked.connect(lambda _, e=entry: self._on_edit(e))
            btn_del.clicked.connect(lambda _, eid=entry["id"]: self._on_delete(eid))
            
            l_act.addWidget(btn_edit)
            l_act.addWidget(btn_del)
            self.table.setCellWidget(row_idx, 6, w_act)

    def _on_edit(self, entry: dict):
        dialog = EditEntryDialog(entry, self._db_path, record_type=self._record_type, parent=self)
        if dialog.exec():
            self.refresh()
            if self._on_deleted: # Tận dụng callback refresh KPI
                self._on_deleted()

    def _on_delete(self, entry_id: int):
        
        main = self.window()
        company_db = getattr(main, "current_db_path", "")

        if self._record_type == "chi":
            entry = get_expense_by_id(entry_id, db_path=self._db_path)
        else:
            entry = get_revenue_by_id(entry_id, db_path=self._db_path)
            
        if not entry:
            return

        reply = QMessageBox.question(
            self, "Xác nhận xóa",
            f"Bạn có chắc muốn xóa bản ghi: {entry.get('note') or entry.get('category_label')}?\n"
            f"Lưu ý: Nếu có liên quan đến kho hàng, hệ thống sẽ tự động hoàn lại tồn kho.",
            QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
        )
        if reply == QMessageBox.StandardButton.Yes:
            # 1. Reverse Inventory if needed
            p_code = entry.get("product_code")
            qty = entry.get("quantity")
            if p_code and qty and qty > 0 and company_db:
                try:
                    import sqlite3
                    conn = sqlite3.connect(company_db)
                    p_row = conn.execute("SELECT id, purchase_price, sale_price FROM products WHERE code=?", (p_code,)).fetchone()
                    conn.close()
                    
                    if p_row:
                        p_id, buy_p, sell_p = p_row
                        is_chi = entry["category"].startswith("chi_")
                        # Nếu là Thu (Bán) -> Giờ xóa Thu -> Nhập lại (In)
                        # Nếu là Chi (Mua) -> Giờ xóa Chi -> Xuất lại (Out)
                        rev_type = "in" if not is_chi else "out"
                        rev_price = sell_p if not is_chi else buy_p
                        
                        add_movement(company_db, p_id, rev_type, qty, rev_price)
                except Exception as ex:
                    print(f"Lỗi hoàn tồn kho: {ex}")

            # 2. Delete Revenue or Expense
            if self._record_type == "chi":
                ok = delete_expense(entry_id, db_path=self._db_path)
            else:
                ok = delete_revenue(entry_id, db_path=self._db_path)
                
            if ok:
                self.refresh()
                if self._on_deleted:
                    self._on_deleted()
            else:
                QMessageBox.warning(self, "Lỗi", "Không thể xóa bản ghi này.")

    def _on_sync_clicked(self):
        """Đồng bộ 2 chiều thu/chi với Google Sheet qua OAuth (tự động)."""
        from core.gs_sync_2way import sync_2way, is_ready
        from core.revenue_db import (
            add_revenue, get_entries_by_month, get_recent_entries,
            add_expense, get_expenses_by_month, get_recent_expenses
        )
        from PySide6.QtWidgets import QApplication

        if not self._db_path or not os.path.exists(self._db_path):
            QMessageBox.warning(self, "Chưa có DB", "Chưa chọn công ty/database. Vào Cài Đặt để chọn.")
            return

        if not is_ready():
            QMessageBox.warning(self, "⚠️ Thiếu thư viện",
                "Chưa cài thư viện cần thiết.\nChạy lệnh:\n\n"
                "pip install gspread google-auth-oauthlib google-api-python-client")
            return

        # Lấy dữ liệu tháng hiện tại
        year_str  = self.combo_year.currentText()
        year      = int(year_str)
        month_idx = self.combo_month.currentIndex()

        # 1. Thu thập dữ liệu
        if month_idx == 0:
            rev_entries = get_recent_entries(limit=1000, db_path=self._db_path)
            exp_entries = get_recent_expenses(limit=1000, db_path=self._db_path)
        else:
            rev_entries = get_entries_by_month(year, month_idx, db_path=self._db_path)
            exp_entries = get_expenses_by_month(year, month_idx, db_path=self._db_path)

        # Spinner
        btn = self.sender()
        orig_text = ""
        if isinstance(btn, QPushButton):
            orig_text = btn.text()
            btn.setText(" ⏳ Đang đồng bộ... ")
            btn.setEnabled(False)
            QApplication.processEvents()

        # 2. Đồng bộ 2 chiều (Thu trước, Chi sau)
        res_thu = sync_2way(rev_entries, year, month_idx, db_path=self._db_path, folder_name="Thu")
        res_chi = sync_2way(exp_entries, year, month_idx, db_path=self._db_path, folder_name="Chi")

        if isinstance(btn, QPushButton):
            btn.setText(orig_text)
            btn.setEnabled(True)

        # 3. Xử lý kết quả
        success = res_thu.get("success") and res_chi.get("success")
        
        if success:
            # Lưu bản ghi Thu mới
            new_rev = 0
            for r in res_thu.get("new_entries", []):
                try:
                    add_revenue(
                        amount=r["amount"], entry_date=r["entry_date"],
                        category=r["category"], note=r.get("note", ""),
                        product_code=r.get("product_code"), quantity=r.get("quantity"),
                        db_path=self._db_path,
                    )
                    new_rev += 1
                except: pass

            # Lưu bản ghi Chi mới
            new_exp = 0
            for r in res_chi.get("new_entries", []):
                try:
                    add_expense(
                        amount=abs(r["amount"]), entry_date=r["entry_date"],
                        category=r["category"], note=r.get("note", ""),
                        product_code=r.get("product_code"), quantity=r.get("quantity"),
                        db_path=self._db_path,
                    )
                    new_exp += 1
                except: pass

            if new_rev or new_exp:
                self.refresh()

            from core.drive_sync import get_drive_parent_name
            parent_name = get_drive_parent_name()

            msg = f"✅ Đồng bộ hoàn tất!\n\n"
            msg += f"· THU: Đẩy {res_thu.get('pushed', 0)}, Tải {new_rev}\n"
            msg += f"· CHI: Đẩy {res_chi.get('pushed', 0)}, Tải {new_exp}\n\n"
            msg += f"Thư mục: {parent_name}/doanhthu/thu và {parent_name}/doanhthu/chi"
            
            box = QMessageBox(self)
            box.setWindowTitle("✅ Đồng bộ hoàn tất")
            box.setIcon(QMessageBox.Icon.Information)
            box.setText(msg)
            btn_open_thu = box.addButton("📂 Mở Sheet Thu", QMessageBox.ButtonRole.ActionRole)
            btn_open_chi = box.addButton("📂 Mở Sheet Chi", QMessageBox.ButtonRole.ActionRole)
            box.addButton(QMessageBox.StandardButton.Ok)
            box.exec()
            
            if box.clickedButton() == btn_open_thu:
                QDesktopServices.openUrl(QUrl(res_thu.get("sheet_url", "")))
            elif box.clickedButton() == btn_open_chi:
                QDesktopServices.openUrl(QUrl(res_chi.get("sheet_url", "")))
        else:
            err_msg = res_thu.get("message", "") or res_chi.get("message", "")
            QMessageBox.warning(self, "⚠️ Lỗi đồng bộ", f"❌ {err_msg}")



# ─────────────────────────────────────────────────────────────────────────────
# Tab 3 — Báo cáo năm
# ─────────────────────────────────────────────────────────────────────────────


class ReportTab(QWidget):
    """Tab biểu đồ tổng hợp năm + cảnh báo ngưỡng thuế."""

    def __init__(self, parent=None):
        super().__init__(parent)
        self._db_path: str = ""
        self._build_ui()

    def _build_ui(self):
        outer = QVBoxLayout(self)
        outer.setContentsMargins(0, 0, 0, 0)

        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setFrameShape(QFrame.Shape.NoFrame)

        body = QWidget()
        body_layout = QVBoxLayout(body)
        body_layout.setContentsMargins(30, 20, 30, 30)
        body_layout.setSpacing(20)

        # ── Năm selector ───────────────────────────────────
        row = QHBoxLayout()
        row.setContentsMargins(0, 0, 0, 0)
        lbl_y = QLabel("Năm:")
        lbl_y.setFont(QFont("Segoe UI", 10))
        
        years = [str(y) for y in range(2026, 2031)]
        self.combo_year = make_combo(years)
        self.combo_year.setCurrentText(str(datetime.now().year))
        self.combo_year.currentIndexChanged.connect(self.refresh)

        btn_reload = SecondaryButton("Cập nhật", icon="🔄")
        btn_reload.clicked.connect(self.refresh)

        row.addWidget(lbl_y)
        row.addWidget(self.combo_year)
        row.addWidget(btn_reload)
        row.addStretch()
        body_layout.addLayout(row)

        # ── Cảnh báo ngưỡng ─────────────────────────────────
        self.warning_banner = WarningBanner()
        body_layout.addWidget(self.warning_banner)

        # ── Tổng năm + Progress bar ─────────────────────────
        self.summary_box = make_group("📊  Tổng kết năm")
        summary_layout = self.summary_box.layout()
        summary_layout.setContentsMargins(20, 16, 20, 16)
        summary_layout.setSpacing(12)

        # Tổng doanh thu
        total_row = QHBoxLayout()
        lbl_total_title = QLabel("Tổng doanh thu:")
        lbl_total_title.setFont(QFont("Segoe UI", 11))

        self.lbl_total_year = QLabel("—")
        self.lbl_total_year.setFont(QFont("Segoe UI", 18, QFont.Weight.Bold))
        self.lbl_total_year.setStyleSheet(
            f"color: {COLORS['accent']}; background: transparent; border: none;"
        )

        total_row.addWidget(lbl_total_title)
        total_row.addStretch()
        total_row.addWidget(self.lbl_total_year)
        summary_layout.addLayout(total_row)

        # Progress bar ngưỡng
        self.lbl_progress_text = QLabel("Đạt 0% ngưỡng miễn thuế 500 triệu")
        self.lbl_progress_text.setFont(QFont("Segoe UI", 9))
        self.lbl_progress_text.setStyleSheet(
            f"color: {COLORS['text_secondary']}; background: transparent;"
        )

        self.progress_bar = QProgressBar()
        self.progress_bar.setMinimum(0)
        self.progress_bar.setMaximum(100)
        self.progress_bar.setValue(0)
        self.progress_bar.setFixedHeight(18)
        self.progress_bar.setTextVisible(False)
        self.progress_bar.setStyleSheet("""
            QProgressBar {
                border: 1px solid #e2e8f0;
                border-radius: 9px;
                background: #f8fafc;
            }
            QProgressBar::chunk {
                border-radius: 9px;
                background: #10b981;
            }
        """)

        summary_layout.addWidget(self.lbl_progress_text)
        summary_layout.addWidget(self.progress_bar)

        body_layout.addWidget(self.summary_box)

        # ── Breakdown 12 tháng ──────────────────────────────
        self.monthly_box = make_group("📅  Chi tiết theo tháng")
        monthly_layout = QGridLayout()
        monthly_layout.setSpacing(8)
        self.monthly_box.layout().addLayout(monthly_layout)

        # Headers
        for col, header in enumerate(["Tháng", "Doanh thu", "Số giao dịch", "% ngưỡng"]):
            lbl = QLabel(header)
            lbl.setFont(QFont("Segoe UI", 9, QFont.Weight.Bold))
            lbl.setStyleSheet(
                f"color: {COLORS['text_secondary']}; background: transparent;"
            )
            monthly_layout.addWidget(lbl, 0, col)

        self._month_labels: list[tuple[QLabel, QLabel, QLabel, QLabel]] = []
        for i in range(12):
            row_idx = i + 1
            lbl_m   = QLabel(f"Tháng {i + 1:02d}")
            lbl_m.setFont(QFont("Segoe UI", 9))
            lbl_amt = QLabel("0 đ")
            lbl_amt.setFont(QFont("Segoe UI", 9))
            lbl_cnt = QLabel("0")
            lbl_cnt.setFont(QFont("Segoe UI", 9))
            lbl_pct = QLabel("0%")
            lbl_pct.setFont(QFont("Segoe UI", 9))

            for col, lbl in enumerate([lbl_m, lbl_amt, lbl_cnt, lbl_pct]):
                lbl.setStyleSheet(f"color: {COLORS['text_primary']}; background: transparent;")
                monthly_layout.addWidget(lbl, row_idx, col)

            self._month_labels.append((lbl_m, lbl_amt, lbl_cnt, lbl_pct))

        body_layout.addWidget(self.monthly_box)

        # ── Lưu ý thuế ────────────────────────────────────
        note_box = CardFrame()
        note_layout = QVBoxLayout(note_box)
        note_layout.setContentsMargins(0, 0, 0, 0)
        note_layout.setSpacing(4)

        note_title = QLabel("💡  Hướng dẫn kê khai (HKD Nhóm 1 — ≤ 500 triệu/năm)")
        note_title.setFont(QFont("Segoe UI", 9, QFont.Weight.Bold))
        note_title.setStyleSheet(f"color: {COLORS['accent']}; background: transparent;")

        notes = [
            "• Miễn thuế GTGT và TNCN nếu doanh thu ≤ 500 triệu/năm (từ 01/01/2026).",
            "• Vẫn phải nộp Thông báo doanh thu thực tế trước 31/01 hằng năm.",
            "• Dùng app eTax Mobile hoặc canhan.gdt.gov.vn để nộp trực tuyến.",
        ]
        note_layout.addWidget(note_title)
        for n in notes:
            lbl = QLabel(n)
            lbl.setFont(QFont("Segoe UI", 9))
            lbl.setStyleSheet(f"color: {COLORS['text_secondary']}; background: transparent;")
            lbl.setWordWrap(True)
            note_layout.addWidget(lbl)

        body_layout.addWidget(note_box)
        body_layout.addStretch()

        scroll.setWidget(body)
        outer.addWidget(scroll)

        # First load
        self.refresh()

    def refresh(self):
        """Cập nhật toàn bộ báo cáo."""
        if not self._db_path or not os.path.exists(self._db_path):
            self.lbl_total_year.setText("—")
            self.lbl_progress_text.setText("Chưa chọn công ty/database")
            self.progress_bar.setValue(0)
            self.warning_banner.setVisible(False)
            for _, lbl_amt, lbl_cnt, lbl_pct in self._month_labels:
                lbl_amt.setText("0 đ")
                lbl_cnt.setText("0")
                lbl_pct.setText("0%")
            return

        try:
            year = int(self.combo_year.currentText())
        except ValueError:
            year = datetime.now().year

        data = get_yearly_summary(year, db_path=self._db_path)
        total          = data["total"]
        pct            = data["threshold_pct"]
        monthly        = data["monthly_breakdown"]
        warning_level  = data["warning_level"]

        # Total label
        self.lbl_total_year.setText(_fmt_vnd(total))
        color = COLORS["danger"] if warning_level == "danger" else \
                COLORS["warning"] if warning_level == "warning" else \
                COLORS["accent"]
        self.lbl_total_year.setStyleSheet(
            f"color: {color}; background: transparent; border: none;"
        )

        # Progress bar
        bar_val = min(100, int(pct))
        self.progress_bar.setValue(bar_val)
        bar_color = COLORS["danger"] if warning_level == "danger" else \
                    COLORS["warning"] if warning_level == "warning" else \
                    COLORS["success"]
        self.progress_bar.setStyleSheet(f"""
            QProgressBar {{
                border: 1px solid #e2e8f0;
                border-radius: 9px;
                background: #f8fafc;
            }}
            QProgressBar::chunk {{
                border-radius: 9px;
                background: {bar_color};
            }}
        """)
        self.lbl_progress_text.setText(
            f"Đạt {pct:.1f}% ngưỡng miễn thuế 500 triệu  "
            f"({_fmt_vnd(total)} / {_fmt_vnd(REVENUE_THRESHOLD)})"
        )

        # Warning banner
        self.warning_banner.update_warning(warning_level, pct, total)

        # Monthly breakdown
        for i, m_data in enumerate(monthly):
            m_total = m_data["total"]
            m_count = m_data["count"]
            m_pct   = (m_total / REVENUE_THRESHOLD * 100) if REVENUE_THRESHOLD > 0 else 0

            _, lbl_amt, lbl_cnt, lbl_pct = self._month_labels[i]
            lbl_amt.setText(_fmt_vnd(m_total) if m_total > 0 else "—")
            lbl_cnt.setText(str(m_count))
            lbl_pct.setText(f"{m_pct:.1f}%" if m_total > 0 else "—")

            # Highlight
            if m_total > 0:
                lbl_amt.setStyleSheet(
                    f"color: {COLORS['success']}; background: transparent; font-weight: bold;"
                )
            else:
                lbl_amt.setStyleSheet(
                    f"color: {COLORS['text_muted']}; background: transparent;"
                )


# ─────────────────────────────────────────────────────────────────────────────
# Main Page
# ─────────────────────────────────────────────────────────────────────────────

class RevenuePage(QWidget):
    """Trang chính — Sổ Tay Thu / Chi."""

    def __init__(self, parent=None):
        super().__init__(parent)
        self.setObjectName("content_area")
        self._db_path: str = ""
        self._build_ui()

        # Auto-refresh KPIs every 60 seconds
        self._timer = QTimer(self)
        self._timer.timeout.connect(self._refresh_kpis)
        self._timer.start(60_000)

    def _build_ui(self):
        root = QVBoxLayout(self)
        root.setContentsMargins(16, 16, 16, 16)
        root.setSpacing(0)

        # ── KPI Bar ────────────────────────────────────────
        kpi_widget = QWidget()
        kpi_layout = QHBoxLayout(kpi_widget)
        kpi_layout.setContentsMargins(0, 0, 0, 16)
        kpi_layout.setSpacing(12)

        self.kpi_today  = KpiCard("🌞  Hôm nay",       "—", COLORS["text_primary"])
        self.kpi_month  = KpiCard("📅  Tháng này",      "—", COLORS["accent"])
        self.kpi_year   = KpiCard("📆  Năm nay",        "—", COLORS["accent_light"])
        self.kpi_pct    = KpiCard("📊  % ngưỡng 500M",  "—", COLORS["success"])

        for card in [self.kpi_today, self.kpi_month, self.kpi_year, self.kpi_pct]:
            kpi_layout.addWidget(card)

        root.addWidget(kpi_widget)

        # ── Tabs ──────────────────────────────────────────
        self.tabs = QTabWidget()
        self.tabs.setObjectName("tab_main")

        self._entry_tab   = QuickEntryTab(on_saved_callback=self._on_entry_saved)
        self._history_thu = HistoryTab(record_type="thu", on_deleted_callback=self._refresh_kpis)
        self._history_chi = HistoryTab(record_type="chi", on_deleted_callback=self._refresh_kpis)
        self._report_tab  = ReportTab()

        self.tabs.addTab(self._entry_tab,   "✏️  NHẬP NHANH")
        self.tabs.addTab(self._history_thu, "📉  LỊCH SỬ DOANH THU")
        self.tabs.addTab(self._history_chi, "💸  LỊCH SỬ CHI PHÍ")
        self.tabs.addTab(self._report_tab,  "📊  BIỂU ĐỒ NĂM")

        # Connect tab change to refresh products
        self.tabs.currentChanged.connect(self._on_tab_changed)

        root.addWidget(self.tabs)

        # Load KPIs
        self._refresh_kpis()
        self._entry_tab._refresh_products()

    def _on_entry_saved(self):
        """Callback sau mỗi lần lưu thành công."""
        self._refresh_kpis()
        self._history_thu.refresh()
        self._history_chi.refresh()
        self._report_tab.refresh()
        self._entry_tab._refresh_products()

    def _on_tab_changed(self, index):
        """Kích hoạt khi chuyển tab."""
        if index == 0:
            self._entry_tab._refresh_products()
        elif index == 1:
            self._history_thu.refresh()
        elif index == 2:
            self._history_chi.refresh()
        elif index == 3:
            self._report_tab.refresh()

    def _refresh_kpis(self):
        """Cập nhật 4 thẻ KPI."""
        if not self._db_path or not os.path.exists(self._db_path):
            self.kpi_today.set_value("—")
            self.kpi_month.set_value("—")
            self.kpi_year.set_value("—")
            self.kpi_pct.set_value("—")
            self.kpi_pct.set_color(COLORS["success"])
            return

        now = datetime.now()
        today_str = now.strftime("%Y-%m-%d")

        try:
            today_data = get_daily_summary(today_str, db_path=self._db_path)
            month_data = get_monthly_summary(now.year, now.month, db_path=self._db_path)
            year_data  = get_yearly_summary(now.year, db_path=self._db_path)

            self.kpi_today.set_value(_fmt_vnd_short(today_data["total"]))
            self.kpi_month.set_value(_fmt_vnd_short(month_data["total"]))
            self.kpi_year.set_value(_fmt_vnd_short(year_data["total"]))

            pct = year_data["threshold_pct"]
            self.kpi_pct.set_value(f"{pct:.1f}%")

            # Color cho % KPI
            if pct >= 100:
                self.kpi_pct.set_color(COLORS["danger"])
            elif pct >= 80:
                self.kpi_pct.set_color(COLORS["warning"])
            else:
                self.kpi_pct.set_color(COLORS["success"])

        except Exception as e:
            print(f"[RevenuePage] Lỗi refresh KPIs: {e}")

    def open_contract_entry(self, kind: str, contract: dict):
        self.tabs.setCurrentIndex(0)
        self._entry_tab.prefill_from_contract(kind, contract)

    def refresh(self, db_path: str = ""):
        """Được gọi từ MainWindow khi switch page hoặc DB thay đổi."""
        if db_path:
            init_revenue_db(db_path)
            self._db_path = db_path
            # Truyền db_path mới xuống các tab con
            self._entry_tab._db_path   = db_path
            self._history_thu._db_path = db_path
            self._history_chi._db_path = db_path
            self._report_tab._db_path  = db_path
        self._refresh_kpis()
        self._history_thu.refresh()
        self._history_chi.refresh()
        self._report_tab.refresh()
        self._entry_tab._refresh_products()
