"""Configurable attribute/option requirements for Magento sync and catalog provision."""

from __future__ import annotations

import re
from typing import Any, Dict, List, Optional, Set, Tuple

from normalize import _is_empty

_NON_CONFIGURABLE_AXIS_CODES = frozenset(
    {
        "variation_option_label",
        "item_size",
        "sku",
    }
)

_CANONICAL_TO_MAGENTO_AXIS: Dict[str, str] = {
    "variation_width_in": "width",
    "variation_height_in": "height",
    "variation_depth_in": "depth",
    "width_in": "width",
    "height_in": "height",
    "depth_in": "depth",
}

_ATTR_CODE_RE = re.compile(r"^[a-z][a-z0-9_]{0,63}$")


def is_valid_attribute_code(code: object) -> bool:
    if _is_empty(code):
        return False
    text = str(code).strip().lower()
    if text in _NON_CONFIGURABLE_AXIS_CODES:
        return False
    return bool(_ATTR_CODE_RE.match(text))


def resolve_magento_axis_code(code: object) -> Optional[str]:
    if _is_empty(code):
        return None
    raw = str(code).strip().lower()
    if "=" in raw:
        raw = raw.split("=", 1)[0].strip()
    mapped = _CANONICAL_TO_MAGENTO_AXIS.get(raw, raw)
    return mapped if is_valid_attribute_code(mapped) else None


def sanitize_attribute_code_list(codes: List[str]) -> List[str]:
    seen: set[str] = set()
    out: List[str] = []
    for code in codes:
        resolved = resolve_magento_axis_code(code)
        if resolved and resolved not in seen:
            seen.add(resolved)
            out.append(resolved)
    return out


def extract_configurable_requirements(
    snapshot_rows: List[Dict[str, Any]],
) -> Tuple[Set[str], Dict[str, str], Dict[str, Set[str]]]:
    """
    Collect Magento channel attribute codes and select-option labels from snapshot rows.

    Returns (attribute_codes, code_to_frontend_label, option_labels_by_attr).
    """
    from magento.sync_hashes import _parse_children_from_row

    codes: Set[str] = set()
    code_to_label: Dict[str, str] = {}
    option_labels: Dict[str, Set[str]] = {}

    for row in snapshot_rows:
        attrs_raw = str(row.get("configurable_attributes", "")).strip()
        if attrs_raw and not _is_empty(attrs_raw):
            for part in attrs_raw.split(","):
                part = part.strip()
                if not part:
                    continue
                if "=" in part:
                    raw_code, label = part.split("=", 1)
                    channel_code = resolve_magento_axis_code(raw_code)
                    if channel_code:
                        codes.add(channel_code)
                        label_text = str(label).strip()
                        if label_text:
                            code_to_label.setdefault(channel_code, label_text)
                else:
                    channel_code = resolve_magento_axis_code(part)
                    if channel_code:
                        codes.add(channel_code)

        _, mappings, _ = _parse_children_from_row(row)
        for mapping in mappings:
            for raw_attr, label in mapping.items():
                channel_code = resolve_magento_axis_code(raw_attr)
                if not channel_code:
                    continue
                codes.add(channel_code)
                label_text = str(label or "").strip()
                if label_text and not _is_empty(label_text):
                    option_labels.setdefault(channel_code, set()).add(label_text)

    for attr_code in codes:
        option_labels.setdefault(attr_code, set())
    return codes, code_to_label, option_labels
