from __future__ import annotations
from typing import Callable

from PySide6.QtCore import QTimer, QEvent, Qt
from PySide6.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton,
    QTableWidget, QTableWidgetItem, QAbstractItemView, QHeaderView
)

from mi100.repository import Repo
from mi100.ui.client_detail import ClientDetail
from mi100.ui.delegates import RowTintDelegate


class ClientsPage(QWidget):
    def __init__(self, repo: Repo, open_right_panel: Callable[[QWidget, str], None]):
        super().__init__()
        self.repo = repo
        self.open_right_panel = open_right_panel
        self._row_by_client_id: dict[int, int] = {}
        self._debtors_only = False

        self._search_timer = QTimer(self)
        self._search_timer.setSingleShot(True)
        self._search_timer.setInterval(200)
        self._search_timer.timeout.connect(self.refresh)

        self._build()
        self.refresh()

    def _build(self) -> None:
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(10)

        top = QHBoxLayout()

        self.search = QLineEdit()
        self.search.setPlaceholderText("Пошук: компанія / контакт / email / телефон")
        self.search.textChanged.connect(lambda: self._search_timer.start())

        self.btn_debtors = QPushButton("Показати боржників")
        self.btn_debtors.setCheckable(True)
        self.btn_debtors.setObjectName("Primary")
        self.btn_debtors.toggled.connect(self._toggle_debtors)

        self.btn_new = QPushButton("＋")
        self.btn_new.setFixedSize(32, 32)
        self.btn_new.setObjectName("Primary")
        f = self.btn_new.font()
        f.setPointSize(max(12, f.pointSize()))
        self.btn_new.setFont(f)
        self.btn_new.clicked.connect(self._create_client)

        top.addWidget(self.search, 1)
        top.addWidget(self.btn_debtors)
        top.addWidget(self.btn_new)
        layout.addLayout(top)

        self.table = QTableWidget(0, 6)
        self.table.setHorizontalHeaderLabels(["Компанія", "Контактна особа", "Email", "Телефон", "Борг", "Баланс"])
        self.table.setAlternatingRowColors(False)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)

        self._row_delegate = RowTintDelegate(self.table)
        self.table.setItemDelegate(self._row_delegate)
        self.table.setMouseTracking(True)
        self.table.cellEntered.connect(self._on_hover_cell)
        self.table.viewport().installEventFilter(self)
        self.table.cellClicked.connect(self._open_selected)
        self.table.verticalHeader().setVisible(False)
        self.table.setWordWrap(True)
        self.table.horizontalHeader().setMinimumSectionSize(70)
        self.table.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeToContents)
        self.table.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeToContents)
        self.table.setColumnWidth(0, 150)
        self.table.setColumnWidth(1, 150)
        self.table.setColumnWidth(2, 150)
        self.table.setColumnWidth(3, 130)
        self.table.setColumnWidth(4, 78)
        self.table.setColumnWidth(5, 78)

        layout.addWidget(self.table, 1)

        self.footer = QLabel("")
        self.footer.setStyleSheet("color:#666;")
        layout.addWidget(self.footer)

    def eventFilter(self, obj, event):
        if obj is self.table.viewport() and event.type() == QEvent.Type.Leave:
            self._row_delegate.set_hover_row(-1)
            self.table.viewport().update()
        return super().eventFilter(obj, event)

    def _on_hover_cell(self, row: int, _col: int) -> None:
        self._row_delegate.set_hover_row(row)
        self.table.viewport().update()

    def _toggle_debtors(self, on: bool) -> None:
        self._debtors_only = bool(on)
        self.btn_debtors.setText("Показати всіх" if self._debtors_only else "Показати боржників")
        self.btn_debtors.setObjectName("Warn" if self._debtors_only else "Primary")
        self.btn_debtors.style().unpolish(self.btn_debtors)
        self.btn_debtors.style().polish(self.btn_debtors)
        self.refresh()

    def _create_client(self) -> None:
        w = ClientDetail(
            self.repo,
            None,
            on_deleted=self._on_client_deleted,
            on_updated=lambda cid: self._update_row(cid),
        )
        self.open_right_panel(w, "")

    def refresh(self, select_client_id: int | None = None) -> None:
        rows = self.repo.list_clients(search=self.search.text(), debtors_only=self._debtors_only)
        self.table.setRowCount(0)
        self._row_by_client_id = {}

        for r in rows:
            rid = int(r["id"])
            debt = float(r.get('debt', 0.0)) if 'debt' in r.keys() else (float(self.repo.get_client_debt(rid)) if hasattr(self.repo, 'get_client_debt') else 0.0)
            balance = float(r.get('balance', 0.0)) if 'balance' in r.keys() else (float(self.repo.get_client_balance(rid)) if hasattr(self.repo, 'get_client_balance') else 0.0)

            row_idx = self.table.rowCount()
            self.table.insertRow(row_idx)
            self._row_by_client_id[rid] = row_idx

            vals = [
                r["company_name"] or r["display_name"] or "",
                r["responsible_person_name"] or "",
                r["email"] or "",
                r["phone"] or "",
                str(r.get('debt_display') or (str(int(debt)) if debt.is_integer() else f"{debt:.2f}")),
                str(r.get('balance_display') or (str(int(balance)) if balance.is_integer() else f"{balance:.2f}")),
            ]

            color_key = "green" if debt > 0 else ("blue" if balance > 0 else "white")

            for c, text in enumerate(vals):
                it = QTableWidgetItem(text)
                if c in (4, 5):
                    it.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                it.setData(RowTintDelegate.ROLE_BG_KEY, color_key)
                self.table.setItem(row_idx, c, it)

            self.table.setVerticalHeaderItem(row_idx, QTableWidgetItem(str(rid)))

        total_debt_map = self.repo.get_total_clients_debt_map() if hasattr(self.repo, 'get_total_clients_debt_map') else {'UAH': float(self.repo.get_total_clients_debt()) if hasattr(self.repo, 'get_total_clients_debt') else 0.0}
        self.footer.setText('Загальна сума боргу з урахуванням балансу:\n' + self.repo.format_currency_map(total_debt_map))


        self.table.resizeColumnsToContents()
        self.table.setColumnWidth(0, max(self.table.columnWidth(0), 180))
        self.table.setColumnWidth(1, max(self.table.columnWidth(1), 170))
        self.table.setColumnWidth(2, max(self.table.columnWidth(2), 150))
        self.table.setColumnWidth(3, max(self.table.columnWidth(3), 150))
        self.table.setColumnWidth(4, max(self.table.columnWidth(4), 80))
        self.table.setColumnWidth(5, max(self.table.columnWidth(5), 80))
        self.table.resizeRowsToContents()
        for row_idx in range(self.table.rowCount()):
            self.table.setRowHeight(row_idx, max(18, min(22, self.table.rowHeight(row_idx))))

        if select_client_id is not None:
            for i in range(self.table.rowCount()):
                if int(self.table.verticalHeaderItem(i).text()) == int(select_client_id):
                    self.table.selectRow(i)
                    break

    def _update_row(self, client_id: int) -> None:
        self.refresh(select_client_id=int(client_id))

    def _selected_client_id(self) -> int | None:
        row = self.table.currentRow()
        if row < 0:
            return None
        try:
            return int(self.table.verticalHeaderItem(row).text())
        except Exception:
            return None

    def _open_selected(self, row: int, col: int) -> None:
        try:
            self.table.setCurrentCell(row, col)
        except Exception:
            pass

        cid = self._selected_client_id()
        if cid is not None:
            self._open_client(cid)

    def _open_client(self, client_id: int) -> None:
        w = ClientDetail(
            self.repo,
            client_id,
            on_deleted=self._on_client_deleted,
            on_updated=lambda cid: self._update_row(cid),
        )
        self.open_right_panel(w, w.company_name.text() or "")

    def _on_client_deleted(self, client_id: int) -> None:
        self.refresh()
        self.open_right_panel(QWidget(), "")