from __future__ import annotations

from typing import Any, Mapping


EXECUTION_CONTRACT_SCALAR_FIELDS = (
    "writer_owner",
    "execution_owner_mode",
    "strategy_id",
    "instance_id",
    "attributed_strategy_id",
    "attributed_instance_id",
    "selected_strategy_id",
    "selected_instance_id",
    "entry_owner_instance_id",
    "entry_owner_strategy_id",
    "current_manager_instance_id",
    "current_manager_strategy_id",
    "expected_exit_owner_instance_id",
    "expected_exit_owner_strategy_id",
    "exit_owner_instance_id",
    "exit_owner_strategy_id",
)
EXECUTION_CONTRACT_LIST_FIELDS = ("contributors",)
EXECUTION_CONTRACT_DICT_FIELDS = ("risk_decision",)
EXECUTION_CONTRACT_FIELDS = (
    *EXECUTION_CONTRACT_SCALAR_FIELDS,
    *EXECUTION_CONTRACT_LIST_FIELDS,
    *EXECUTION_CONTRACT_DICT_FIELDS,
)


def _normalized_scalar(value: Any) -> Any:
    if isinstance(value, str):
        value = value.strip()
    return value


def _is_empty(value: Any) -> bool:
    if value is None:
        return True
    if isinstance(value, str):
        return not value.strip()
    if isinstance(value, (list, dict, tuple, set)):
        return not value
    return False


def extract_execution_contract_fields(*payloads: Mapping[str, Any]) -> dict[str, Any]:
    contract: dict[str, Any] = {}
    for payload in payloads:
        if not isinstance(payload, Mapping):
            continue
        for field in EXECUTION_CONTRACT_SCALAR_FIELDS:
            if field in contract and not _is_empty(contract.get(field)):
                continue
            value = _normalized_scalar(payload.get(field))
            if _is_empty(value):
                continue
            contract[field] = value
        for field in EXECUTION_CONTRACT_LIST_FIELDS:
            if field in contract and not _is_empty(contract.get(field)):
                continue
            value = payload.get(field)
            if not isinstance(value, list) or not value:
                continue
            contract[field] = list(value)
        for field in EXECUTION_CONTRACT_DICT_FIELDS:
            if field in contract and not _is_empty(contract.get(field)):
                continue
            value = payload.get(field)
            if not isinstance(value, dict) or not value:
                continue
            contract[field] = dict(value)
    return contract


def apply_execution_contract_defaults(target: dict[str, Any], *payloads: Mapping[str, Any]) -> dict[str, Any]:
    if not isinstance(target, dict):
        return target
    for field, value in extract_execution_contract_fields(*payloads).items():
        if field not in target or _is_empty(target.get(field)):
            target[field] = value
    return target
