"""AbstractCore output-selector helpers used by Runtime effect wiring and clients."""

from __future__ import annotations

from typing import Any, Dict, List, Optional

_ACORE_OUTPUT_MODALITY_ALIASES = {
    "speech": ("voice", "tts"),
    "tts": ("voice", "tts"),
    "audio": ("voice", "tts"),
    "transcript": ("text", "transcription"),
    "transcription": ("text", "transcription"),
    "t2i": ("image", "image_generation"),
    "image_generation": ("image", "image_generation"),
    "i2i": ("image", "image_edit"),
    "image_to_image": ("image", "image_edit"),
    "image_edit": ("image", "image_edit"),
}

_ACORE_OUTPUT_TASK_ALIASES = {
    "speech": "tts",
    "audio": "tts",
    "clone": "voice_clone",
    "transcript": "transcription",
    "t2i": "image_generation",
    "i2i": "image_edit",
    "image_to_image": "image_edit",
}

_ACORE_OUTPUT_STRING_VALUES = {
    "text",
    "transcript",
    "transcription",
    "image",
    "voice",
    "speech",
    "tts",
    "audio",
}

_ACORE_OUTPUT_DICT_VALUES = {
    "text",
    "transcript",
    "transcription",
    "text_generation",
    "image",
    "image_generation",
    "image_edit",
    "t2i",
    "i2i",
    "image_to_image",
    "voice",
    "speech",
    "tts",
    "voice_clone",
    "clone",
}


def is_abstractcore_output_request(output: Any) -> bool:
    """Return True when `output` is AbstractCore's multimodal output selector."""

    if output is None:
        return False
    if isinstance(output, str):
        return output.strip().lower() in _ACORE_OUTPUT_STRING_VALUES
    if isinstance(output, (list, tuple)):
        return bool(output) and all(is_abstractcore_output_request(item) for item in output)
    if isinstance(output, dict):
        raw = output.get("modality", output.get("type", output.get("output")))
        task = output.get("task")
        values = {str(v).strip().lower() for v in (raw, task) if isinstance(v, str) and v.strip()}
        return bool(values & _ACORE_OUTPUT_DICT_VALUES)
    return False


def normalize_output_spec_for_runtime(output: Any) -> Dict[str, Any]:
    """Normalize an AbstractCore output selector using the same public aliases as core."""

    if isinstance(output, str):
        spec: Dict[str, Any] = {"modality": output}
    elif isinstance(output, dict):
        spec = dict(output)
        spec["modality"] = spec.get("modality", spec.get("type", spec.get("output")))
    else:
        raise ValueError("output must be a string, dict, or list of output specs")

    modality = str(spec.get("modality") or "").strip().lower()
    task = str(spec.get("task") or "").strip().lower()

    if modality in _ACORE_OUTPUT_MODALITY_ALIASES:
        modality, default_task = _ACORE_OUTPUT_MODALITY_ALIASES[modality]
        task = task or default_task

    if task in _ACORE_OUTPUT_TASK_ALIASES:
        task = _ACORE_OUTPUT_TASK_ALIASES[task]

    if not modality:
        if task in {"tts", "voice_clone"}:
            modality = "voice"
        elif task in {"transcription"}:
            modality = "text"
        elif task in {"image_generation", "image_edit"}:
            modality = "image"

    spec["modality"] = modality
    if task:
        spec["task"] = task
    return spec


def normalize_output_specs_for_runtime(output: Any) -> List[Dict[str, Any]]:
    if isinstance(output, (list, tuple)):
        return [normalize_output_spec_for_runtime(item) for item in output]
    return [normalize_output_spec_for_runtime(output)]


def strip_runtime_output_metadata_for_core(output: Any) -> Any:
    """Keep runtime artifact metadata out of AbstractCore capability kwargs."""

    if isinstance(output, (list, tuple)):
        return [strip_runtime_output_metadata_for_core(item) for item in output]
    if not isinstance(output, dict):
        return output

    spec = dict(output)
    # Runtime stores generated bytes after normalization. Keep artifact metadata
    # away from provider/capability kwargs that may receive output specs directly.
    for key in ("run_id", "tags", "artifact_id"):
        spec.pop(key, None)
    return spec


def output_runtime_metadata(output: Any) -> tuple[Optional[str], Dict[str, Any]]:
    """Extract runtime storage metadata from an AbstractCore output selector."""

    if not is_abstractcore_output_request(output):
        return None, {}

    specs = normalize_output_specs_for_runtime(output)
    run_id: Optional[str] = None
    tags: Dict[str, Any] = {}
    for spec in specs:
        raw_run_id = spec.get("run_id")
        if run_id is None and isinstance(raw_run_id, str) and raw_run_id.strip():
            run_id = raw_run_id.strip()

        raw_tags = spec.get("tags")
        if isinstance(raw_tags, dict):
            tags.update({str(k): str(v) for k, v in raw_tags.items() if k is not None and v is not None})

    return run_id, tags


def output_request_has_generated_media(output: Any) -> bool:
    """Return True when an output selector can produce generated binary media."""

    if not is_abstractcore_output_request(output):
        return False
    specs = normalize_output_specs_for_runtime(output)
    return any(str(spec.get("modality") or "").strip().lower() != "text" for spec in specs)


def output_request_has_non_text_result(output: Any) -> bool:
    if not is_abstractcore_output_request(output):
        return False
    specs = normalize_output_specs_for_runtime(output)
    for spec in specs:
        modality = str(spec.get("modality") or "").strip().lower()
        task = str(spec.get("task") or "").strip().lower()
        if modality != "text" or task == "transcription":
            return True
    return False
