from __future__ import annotations

from typing import Any, Callable

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

from mi100.repository import Repo
from mi100.ui.delegates import RowTintDelegate
from mi100.ui.project_detail import ProjectDetail


class ProjectsPage(QWidget):
    COL_NUM = 0
    COL_DATE = 1
    COL_TITLE = 2
    COL_CLIENT = 3
    COL_WORK = 4
    COL_AMOUNT = 5

    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_id: dict[int, int] = {}
        self._active_only = False
        self._build_ui()
        self.refresh()

    def _build_ui(self) -> None:
        root = QVBoxLayout(self)
        root.setContentsMargins(12, 12, 12, 12)
        root.setSpacing(10)

        header = QHBoxLayout(); header.setSpacing(10)
        self.btn_add = QPushButton("＋")
        self.btn_add.setFixedSize(32, 32)
        self.btn_add.setObjectName("Primary")
        f = self.btn_add.font(); f.setPointSize(max(12, f.pointSize())); self.btn_add.setFont(f)
        self.btn_add.clicked.connect(self._create_project)

        self.btn_toggle_active = QPushButton("Показати актуальні")
        self.btn_toggle_active.setCheckable(True)
        self.btn_toggle_active.setObjectName("Primary")
        self.btn_toggle_active.toggled.connect(self._on_toggle_active)

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

        self.summary = QLabel("")
        self.summary.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.summary.setObjectName("muted")

        self.search = QLineEdit()
        self.search.setPlaceholderText("Пошук: дата / проєкт / замовник")
        self.search.textChanged.connect(self.refresh)
        header.addWidget(self.search, 1)
        header.addWidget(self.btn_toggle_active)
        header.addWidget(self.btn_toggle_unpaid)
        header.addWidget(self.btn_add)
        root.addLayout(header)
        root.addWidget(self.summary)

        self.table = QTableWidget(0, 6)
        self.table.setHorizontalHeaderLabels(["№", "Дата", "Проєкт", "Замовник", "Статус", "Сума"])
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.table.setAlternatingRowColors(False)
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.table.verticalHeader().setVisible(False)
        self.table.horizontalHeader().setMinimumSectionSize(56)
        self.table.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        self.table.setWordWrap(True)
        self.table.horizontalHeader().setSectionResizeMode(self.COL_NUM, QHeaderView.ResizeToContents)
        self.table.horizontalHeader().setSectionResizeMode(self.COL_DATE, QHeaderView.ResizeToContents)
        self.table.horizontalHeader().setSectionResizeMode(self.COL_TITLE, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(self.COL_CLIENT, QHeaderView.Stretch)
        self.table.horizontalHeader().setSectionResizeMode(self.COL_WORK, QHeaderView.ResizeToContents)
        self.table.horizontalHeader().setSectionResizeMode(self.COL_AMOUNT, QHeaderView.ResizeToContents)
        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._on_table_clicked)
        root.addWidget(self.table, 1)

    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 _apply_toggle_style(self, btn: QPushButton, on: bool) -> None:
        btn.setObjectName("Warn" if on else "Primary")
        btn.style().unpolish(btn); btn.style().polish(btn)

    def _on_toggle_debtors(self, on: bool) -> None:
        self.btn_toggle_unpaid.setText("Показати всіх" if on else "Показати боржників")
        self._apply_toggle_style(self.btn_toggle_unpaid, on)
        self.refresh()

    def _on_toggle_active(self, on: bool) -> None:
        self._active_only = bool(on)
        self.btn_toggle_active.setText("Показати всі" if on else "Показати актуальні")
        self._apply_toggle_style(self.btn_toggle_active, on)
        self.refresh()

    def refresh(self) -> None:
        rows = self.repo.list_projects(show_all=True, show_debtors_only=bool(self.btn_toggle_unpaid.isChecked()))
        q = self.search.text().strip().lower() if hasattr(self, 'search') else ''
        if q:
            rows = [r for r in rows if q in str(r.get('created_date') or '').lower() or q in str(r.get('title') or '').lower() or q in str(r.get('client_name') or '').lower()]
        if self._active_only:
            rows = [r for r in rows if str(r.get("work_status") or "").upper() == "IN_PROGRESS"]

        self.table.setRowCount(0)
        self._row_by_id.clear()
        debtor_clients: set[int] = set()
        debt_by_currency: dict[str, float] = {}

        grouped = [
            ('Проєкти в роботі (не оплачені)', [r for r in rows if str(r.get('work_status') or '').upper() == 'IN_PROGRESS' and int(r.get('client_paid') or 0) == 0]),
            ('Проєкти в роботі (оплачені)', [r for r in rows if str(r.get('work_status') or '').upper() == 'IN_PROGRESS' and int(r.get('client_paid') or 0) == 1]),
            ('Завершені проєкти (не оплачені)', [r for r in rows if str(r.get('work_status') or '').upper() == 'COMPLETED' and int(r.get('client_paid') or 0) == 0]),
            ('Завершені проєкти (оплачені)', [r for r in rows if str(r.get('work_status') or '').upper() == 'COMPLETED' and int(r.get('client_paid') or 0) == 1]),
        ]

        for group_title, group_rows in grouped:
            if not group_rows:
                continue
            hdr = self.table.rowCount()
            self.table.insertRow(hdr)
            self.table.setSpan(hdr, 0, 1, self.table.columnCount())
            hdr_item = QTableWidgetItem(group_title)
            hdr_item.setFlags(Qt.ItemIsEnabled)
            hdr_item.setTextAlignment(Qt.AlignCenter)
            f = hdr_item.font(); f.setBold(True); f.setPointSize(14); hdr_item.setFont(f)
            self.table.setItem(hdr, 0, hdr_item)
            self.table.setRowHeight(hdr, 28)

            for r in group_rows:
                pid = int(r["id"])
                paid = int(r.get("client_paid") or 0)
                amount = float(r.get("total_amount") or 0.0)
                currency = r.get("currency") or "UAH"
                if paid == 0:
                    try:
                        debtor_clients.add(int(r.get("client_id") or 0))
                    except Exception:
                        pass
                    debt_by_currency[currency] = debt_by_currency.get(currency, 0.0) + amount
                color_key = self._project_color_key(r)
                vals = [
                    str(r.get("project_number") or ""),
                    str(r.get("created_date") or ""),
                    str(r.get("title") or ""),
                    str(r.get("client_name") or ""),
                    "",
                    self.repo.format_money(amount, currency),
                ]
                row = self.table.rowCount()
                self.table.insertRow(row)
                self._row_by_id[pid] = row
                for c, text in enumerate(vals):
                    it = QTableWidgetItem(text)
                    if c == self.COL_AMOUNT:
                        it.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                    it.setData(Qt.UserRole, pid)
                    it.setData(RowTintDelegate.ROLE_BG_KEY, color_key)
                    self.table.setItem(row, c, it)
                btn_status = QPushButton('Повернути в роботу' if str(r.get('work_status') or '').upper() == 'COMPLETED' else 'Завершити проєкт')
                btn_status.setFixedHeight(22)
                btn_status.setMinimumWidth(140)
                if str(r.get('work_status') or '').upper() == 'COMPLETED':
                    btn_status.setStyleSheet("QPushButton{background:#FFD8A8; border:1px solid #E5BF90; border-radius:6px; padding:2px 8px; color:#8E6129; font-weight:600;} QPushButton:hover{background:#E5BF90;}")
                else:
                    btn_status.setStyleSheet("QPushButton{background:#4FAF7A; border:1px solid #459E6E; border-radius:6px; padding:2px 8px; color:#FFFFFF; font-weight:600;} QPushButton:hover{background:#459E6E;}")
                btn_status.clicked.connect(lambda _=False, pid=pid, cur=str(r.get('work_status') or 'IN_PROGRESS'): self._toggle_project_work_status(pid, cur))
                self.table.setCellWidget(row, self.COL_WORK, self._make_button_holder(btn_status))

        self.table.resizeColumnsToContents()
        self.table.setColumnWidth(self.COL_NUM, max(self.table.columnWidth(self.COL_NUM), 60))
        self.table.setColumnWidth(self.COL_DATE, max(self.table.columnWidth(self.COL_DATE), 110))
        self.table.setColumnWidth(self.COL_TITLE, max(self.table.columnWidth(self.COL_TITLE), 180))
        self.table.setColumnWidth(self.COL_CLIENT, max(self.table.columnWidth(self.COL_CLIENT), 180))
        self.table.setColumnWidth(self.COL_WORK, max(self.table.columnWidth(self.COL_WORK), 150))
        self.table.setColumnWidth(self.COL_AMOUNT, max(self.table.columnWidth(self.COL_AMOUNT), 160))
        self.table.resizeRowsToContents()
        for row_idx in range(self.table.rowCount()):
            item0 = self.table.item(row_idx, 0)
            if item0 is not None and item0.data(Qt.UserRole) is None and self.table.columnSpan(row_idx, 0) > 1:
                continue
            self.table.setRowHeight(row_idx, max(18, min(22, self.table.rowHeight(row_idx))))
        self.summary.setText('Боржників: ' + str(len([x for x in debtor_clients if x])) + '\nСума боргу:\n' + self.repo.format_currency_map(debt_by_currency))

    def _make_button_holder(self, button: QPushButton) -> QWidget:
        holder = QWidget()
        holder.setAttribute(Qt.WA_StyledBackground, True)
        lay = QHBoxLayout(holder)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.setSpacing(0)
        lay.setAlignment(Qt.AlignCenter)
        lay.addWidget(button, 0, Qt.AlignCenter)
        return holder

    def _on_table_clicked(self, row: int, col: int):
        if col == self.COL_WORK:
            return
        if self.table.columnSpan(row, 0) > 1:
            return
        item = self.table.item(row, 0)
        pid = item.data(Qt.UserRole) if item is not None else None
        if pid:
            self._open_project(int(pid))

    def _toggle_project_work_status(self, project_id: int, current_status: str) -> None:
        new_status = 'IN_PROGRESS' if str(current_status or '').upper() == 'COMPLETED' else 'COMPLETED'
        self.repo.set_project_work_status(int(project_id), new_status)
        self.refresh()
        self._refresh_related_pages()

    def _open_project(self, project_id: int) -> None:
        data = self.repo.get_project(project_id)
        if not data:
            QMessageBox.warning(self, "Помилка", "Проєкт не знайдено.")
            self.refresh(); return
        detail = ProjectDetail(self.repo, data, self._on_project_saved, self._on_project_deleted, parent=self)
        self.open_right_panel(detail, data.get("title") or "")

    def _create_project(self) -> None:
        detail = ProjectDetail(self.repo, None, self._on_project_saved, self._on_project_deleted, parent=self)
        self.open_right_panel(detail, "")

    def _refresh_related_pages(self) -> None:
        try:
            win = self.window()
            for attr in ("actors_page", "clients_page"):
                page = getattr(win, attr, None)
                if page is not None and hasattr(page, "refresh"):
                    try:
                        page.refresh()
                    except Exception:
                        pass
        except Exception:
            pass

    def _on_project_saved(self, project: dict[str, Any]) -> None:
        self.refresh()
        self._refresh_related_pages()

    def _on_project_deleted(self, project_id: int) -> None:
        self.refresh()
        self._refresh_related_pages()

    @staticmethod
    def _project_color_key(row: dict[str, Any]) -> str:
        work_status = str(row.get("work_status") or row.get("work") or "").upper().strip()
        paid = int(row.get("payment_status") or row.get("client_paid") or 0)
        if work_status == "COMPLETED":
            return "gray" if paid > 0 else "red"
        return "yellow" if paid > 0 else "green"