"""Item-view delegates — chip rendering inside table cells.

``StatusChipDelegate`` paints a dot+label chip in any cell whose index
supplies :data:`STATUS_ROLE`; other cells fall back to default
painting. DisplayRole text is untouched (the test contract renders
through the chip). Colour maps for both themes are pre-built once
from tokens and picked per paint from the option palette — the same
self-theming trick as :class:`~...empty.EmptyState`, so no re-theme
wiring or per-row allocation happens (the dashboard perf pin stays
flat).
"""

from __future__ import annotations

from PySide6.QtCore import QRect, QSize, Qt
from PySide6.QtGui import QColor, QFontMetrics, QPainter
from PySide6.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem

from mgf.brand_qt.fonts import mono_font
from mgf.brand_qt.tokens import (
    DARK,
    LIGHT,
    STATE_HUES,
    TEXT_PT,
    WEIGHT,
    SemanticColors,
)

#: Item-data role carrying the chip state key (str) for a cell.
STATUS_ROLE = int(Qt.ItemDataRole.UserRole) + 40

_DOT = 8
_PAD_X = 10
_PAD_Y = 3
_GAP = 6


def _build_map(sem: SemanticColors) -> dict[str, tuple[QColor, QColor, QColor]]:
    """state → (tint bg, strong text, dot hue) as ready QColors."""
    tints = {
        "success": sem.status_success_tint,
        "warning": sem.status_warning_tint,
        "error": sem.status_error_tint,
        "info": sem.status_info_tint,
        "busy": sem.state_busy_tint,
        "derived": sem.state_derived_tint,
        "neutral": sem.bg_muted,
        "quarantine": sem.state_derived_tint,
    }
    strongs = {
        "success": sem.status_success_strong,
        "warning": sem.status_warning_strong,
        "error": sem.status_error_strong,
        "info": sem.status_info_strong,
        "busy": sem.state_busy_strong,
        "derived": sem.state_derived_strong,
        "neutral": sem.text_secondary,
        "quarantine": sem.state_derived_strong,
    }

    def qcolor(value: str) -> QColor:
        if value.startswith("rgba(") and value.endswith(")"):
            parts = value[5:-1].split(",")
            return QColor(int(parts[0]), int(parts[1]), int(parts[2]), round(float(parts[3]) * 255))
        return QColor(value)

    return {
        state: (qcolor(tints[state]), qcolor(strongs[state]), QColor(STATE_HUES[state]))
        for state in STATE_HUES
    }


_LIGHT_MAP = _build_map(LIGHT)
_DARK_MAP = _build_map(DARK)


class StatusChipDelegate(QStyledItemDelegate):
    """Paints STATUS_ROLE cells as brand chips; default otherwise."""

    def paint(
        self,
        painter: QPainter,
        option: QStyleOptionViewItem,
        index: object,
    ) -> None:
        state = index.data(STATUS_ROLE)  # type: ignore[attr-defined]
        if not isinstance(state, str) or state not in STATE_HUES:
            super().paint(painter, option, index)  # type: ignore[arg-type]
            return
        text = index.data(Qt.ItemDataRole.DisplayRole) or ""  # type: ignore[attr-defined]
        dark = option.palette.window().color().lightness() < 128
        tint, strong, hue = (_DARK_MAP if dark else _LIGHT_MAP)[state]

        font = mono_font(TEXT_PT["sm"], WEIGHT["medium"])
        metrics = QFontMetrics(font)
        chip_w = _PAD_X + _DOT + _GAP + metrics.horizontalAdvance(str(text)) + _PAD_X
        chip_h = max(metrics.height() + 2 * _PAD_Y, _DOT + 2 * _PAD_Y)
        cell = option.rect
        chip = QRect(
            cell.x() + 6,
            cell.y() + (cell.height() - chip_h) // 2,
            min(chip_w, cell.width() - 12),
            chip_h,
        )

        painter.save()
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        painter.setPen(Qt.PenStyle.NoPen)
        painter.setBrush(tint)
        painter.drawRoundedRect(chip, chip_h / 2, chip_h / 2)
        dot = QRect(
            chip.x() + _PAD_X,
            chip.y() + (chip.height() - _DOT) // 2,
            _DOT,
            _DOT,
        )
        painter.setBrush(hue)
        painter.drawEllipse(dot)
        painter.setPen(strong)
        painter.setFont(font)
        painter.drawText(
            QRect(
                dot.right() + _GAP,
                chip.y(),
                chip.right() - dot.right() - _GAP - _PAD_X + 2,
                chip.height(),
            ),
            Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft,
            str(text),
        )
        painter.restore()

    def sizeHint(
        self,
        option: QStyleOptionViewItem,
        index: object,
    ) -> QSize:
        base = super().sizeHint(option, index)  # type: ignore[arg-type]
        if isinstance(index.data(STATUS_ROLE), str):  # type: ignore[attr-defined]
            return QSize(base.width() + 2 * _PAD_X + _DOT + _GAP + 12, base.height() + 6)
        return base


__all__ = ["STATUS_ROLE", "StatusChipDelegate"]
