"""
Magento product overrides: apply force/lock rules to outgoing payloads.

- force: override value (sync_lock_reason is NULL) → set field in payload
- lock: preserve Magento (sync_lock_reason is NOT NULL) → exclude field from payload
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Dict, Set


@dataclass
class OverrideSet:
    """Force overrides (sku->field->value) and lock fields (sku->{fields to exclude})."""

    force: Dict[str, Dict[str, str]]  # sku -> field -> value
    lock: Dict[str, Set[str]]  # sku -> fields to exclude from payload


# Magento top-level product fields we can override directly
TOP_LEVEL_FIELDS = frozenset({
    "name", "sku", "price", "status", "visibility", "weight", "url_key",
})


def _upsert_custom_attribute(attrs: list, code: str, value: str) -> None:
    """Add or update custom_attributes entry by attribute_code. No duplicates."""
    for item in attrs:
        if isinstance(item, dict) and item.get("attribute_code") == code:
            item["value"] = value
            return
    attrs.append({"attribute_code": code, "value": value})


def apply_overrides_to_payload(
    payload: Dict[str, Any],
    overrides_force: Dict[str, str],
    locked_fields: Set[str],
) -> Dict[str, Any]:
    """
    Apply Magento overrides to outgoing payload.

    - locked_fields: exclude these from payload (preserve Magento value)
    - overrides_force: set these values (force override)

    Returns a new dict (does not mutate input).
    """
    result = dict(payload)
    if "custom_attributes" in result and result["custom_attributes"]:
        result["custom_attributes"] = [
            dict(a) if isinstance(a, dict) else a
            for a in result["custom_attributes"]
        ]

    # 1. Remove locked fields
    for field in locked_fields:
        result.pop(field, None)
        if field in ("description", "short_description", "meta_title", "meta_description", "meta_keyword"):
            # Remove from custom_attributes
            attrs = result.get("custom_attributes") or []
            result["custom_attributes"] = [
                a for a in attrs
                if isinstance(a, dict) and a.get("attribute_code") != field
            ]

    # 2. Apply force overrides
    for field, value in overrides_force.items():
        if field in locked_fields:
            continue
        value_str = str(value).strip()
        if field in TOP_LEVEL_FIELDS:
            result[field] = value_str
        else:
            # Custom attribute (description, short_description, meta_title, etc.)
            attrs = result.get("custom_attributes")
            if attrs is None:
                attrs = []
                result["custom_attributes"] = attrs
            _upsert_custom_attribute(attrs, field, value_str)

    # Clean up empty custom_attributes
    if result.get("custom_attributes") == []:
        result.pop("custom_attributes", None)

    return result
