"""Client MMML global SafeArea, calculated once from physical client geometry.

ScreenPaddingProvider supplies physical-pixel insets; CalculateAnchor subtracts
CounterPadding in canvas units. These are NOT two UI-unit paddings. The MMML
caller passes no SafeAreaComponent, so per-component and SplitView adjustments
do not belong in this global formula. No game/OS/file access occurs here.
"""
from __future__ import annotations

from collections.abc import Mapping
import math

from .ui_layout import CanvasContext, LayoutError, Rect


def validate_screen_padding(value):
    if not isinstance(value, Mapping) or set(value) != {
            "formula", "platform", "raw_safe_area", "source_refs", "portrait", "landscape"}:
        raise LayoutError("screen padding rules need explicit source/platform/orientation fields")
    if (value["formula"] != "mmml-global-counter-v1" or value["platform"] != "windows-desktop"
            or value["raw_safe_area"] != "physical-client-content"):
        raise LayoutError("unsupported screen padding formula or platform")
    for orientation in ("portrait", "landscape"):
        row = value[orientation]
        if not isinstance(row, Mapping) or set(row) != {"notification_bar_pixels", "counter_padding_ui"}:
            raise LayoutError("invalid screen padding orientation")
        counter = row["counter_padding_ui"]
        if not isinstance(counter, (tuple, list)) or len(counter) != 4:
            raise LayoutError("counter padding must be left/right/top/bottom UI units")
        for number in (row["notification_bar_pixels"], *counter):
            if type(number) not in (int, float) or not math.isfinite(number) or not 0 <= number <= 10000:
                raise LayoutError("invalid screen padding number")
    return value


def calculate_screen_safe_area(context: CanvasContext, rules, *, physical_safe_area=None):
    """Desktop raw Unity safe rect defaults to the measured client content.

    A supplied raw safe rect is physical pixels, top-left oriented; it is not an
    already adjusted canvas SafeArea. Keeping that distinction prevents double
    padding. Serialized editor anchors and Windows DPI are never inputs.
    """
    rules = validate_screen_padding(rules)
    root = context.root_rect
    raw = root if physical_safe_area is None else physical_safe_area
    if not isinstance(raw, Rect) or not root.contains(raw):
        raise LayoutError("physical screen safe area must lie inside the client")
    row = rules[context.orientation]
    screen_padding = (raw.left, root.right-raw.right,
                      max(row["notification_bar_pixels"], raw.top), root.bottom-raw.bottom)
    left, right, top, bottom = (
        max(0.0, pixels-counter*context.scale)
        for pixels, counter in zip(screen_padding, row["counter_padding_ui"]))
    return Rect(left, top, root.width-left-right, root.height-top-bottom)
