"""CS2140401C rule."""
from __future__ import annotations
import re
from bs4 import BeautifulSoup
from ....css_utils import collect_declarations
from ....models import Level, PageReport
from ...base import Rule, RuleMeta, register
from ..._lib.css import _is_relative_or_named, _ABSOLUTE_UNIT_RE


@register
class FontSizeRelativeUnits(Rule):
    """CS2140401C — font-size declarations should not use absolute units only."""

    meta = RuleMeta(
        rule_id="CS2140401C",
        guideline="1.4.4",
        level=Level.AA,
        desc="任何CSS樣式規則均使用具名字型尺寸，或者使用百分比或em等相對字型尺寸單位",
    )

    def _check(self, soup: BeautifulSoup, report: PageReport, *, html: str, url: str, ctx) -> None:
        decls = collect_declarations(soup, url)
        if ctx.freego_compat:
            # Compat mode: skip entire stylesheets that contain display:none /
            # visibility:hidden, so output aligns with the official tool's report.
            sources_to_skip = set()
            for d in decls:
                v = d.value.lower().replace(" ", "")
                if d.prop == "display" and v == "none":
                    sources_to_skip.add(d.source)
                if d.prop == "visibility" and v == "hidden":
                    sources_to_skip.add(d.source)
            decls = [d for d in decls if d.source not in sources_to_skip]
        offenders: list[tuple[str, str]] = []
        for d in decls:
            if d.prop != "font-size":
                continue
            v = d.value.lower()
            if _is_relative_or_named(v):
                continue
            if _ABSOLUTE_UNIT_RE.search(v):
                offenders.append((v, d.source))
        if offenders:
            sample = offenders[0]
            # Compat mode demotes to info so the report shape matches submissions
            # generated by the official tool.
            status = "info" if ctx.freego_compat else "fail"
            report.add(self._issue(
                message=f"font-size 使用絕對單位「{sample[0]}」（共 {len(offenders)} 處），請改用 em / % / rem 等相對單位或具名字型尺寸。",
                snippet=f"{sample[0]} @ {sample[1]}",
                status=status,
            ))
