
import collections.abc
from google.genai import types


def isStructured(*args):
    """
    Check if any of the arguments is a list of dictionaries.
    This indicates structured input (multi-message format).
    """
    return any(
        isinstance(arg, list) and all(isinstance(i, dict) for i in arg)
        for arg in args
    )


def handleTypedFormat(role: str = "user", content: str = ""):
    """
    Format content for Google GenAI APIs.
    """
    role    = role.lower()
    allowed = {"system", "user", "model"}
    if role not in allowed:
        raise ValueError(
            f"Invalid role '{role}'. Must be one of {', '.join(allowed)}."
        )
    if role == "system":
        return types.Part.from_text(text=content)
    return types.Content(role=role, parts=[types.Part.from_text(text=content)])


def handleJsonFormat(role: str = "user", content: str = ""):
    """
    Format content for OpenAI APIs.
    """
    role    = role.lower()
    allowed = {"system", "developer", "user", "assistant"}
    if role not in allowed:
        raise ValueError(
            f"Invalid role '{role}'. Must be one of {', '.join(allowed)}."
        )
    return {'role': role, 'content': content}


def buildGoogleSafetySettings(harassment="BLOCK_NONE", hateSpeech="BLOCK_NONE", sexuallyExplicit="BLOCK_NONE", dangerousContent="BLOCK_NONE"):
    """
    Construct a list of Google GenAI SafetySetting objects.
    """
    harassment        = harassment.upper()
    hate_speech       = hateSpeech.upper()
    sexually_explicit = sexuallyExplicit.upper()
    dangerous_content = dangerousContent.upper()
    allowed_settings  = {"BLOCK_NONE", "BLOCK_LOW", "BLOCK_MEDIUM", "BLOCK_HIGH", "BLOCK_ALL"}
    for name, val in {
        "harassment": harassment, 
        "hate_speech": hate_speech, 
        "sexually_explicit": sexually_explicit, 
        "dangerous_content": dangerous_content
    }.items():
        if val not in allowed_settings:
            raise ValueError(f"Invalid {name} setting: {val}. Must be one of {', '.join(allowed_settings)}.")

    return [
        types.SafetySetting(category="HARM_CATEGORY_HARASSMENT", threshold=harassment),
        types.SafetySetting(category="HARM_CATEGORY_HATE_SPEECH", threshold=hate_speech),
        types.SafetySetting(category="HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold=sexually_explicit),
        types.SafetySetting(category="HARM_CATEGORY_DANGEROUS_CONTENT", threshold=dangerous_content),
    ]


def handleExamples(items, formatFunc):
    """
    Ultra-robust handler for formatting few-shot or behavioral examples.
    Accepts any mix of (role, value) pairs—strings, dicts, numbers, bools, lists, and any nested structure.
    Silently ignores None. Converts numbers and bools to strings.
    """
    def flatten(role, value):
        if value is None:
            return []
        if isinstance(value, dict):
            return [value]
        if isinstance(value, str):
            return [formatFunc(role, value)]
        if isinstance(value, (int, float, bool)):
            return [formatFunc(role, str(value))]
        if isinstance(value, collections.abc.Sequence) and not isinstance(value, (str, bytes, dict)):
            out = []
            for v in value:
                try:
                    out.extend(flatten(role, v))
                except Exception as e:
                    print(f"Warning: Skipped invalid message part for role '{role}': {v!r} ({type(v).__name__}) [{e}]")
            return out
        try:
            return [formatFunc(role, str(value))]
        except Exception as e:
            print(f"Warning: Could not handle value for role '{role}': {value!r} ({type(value).__name__}) [{e}]")
            return []

    out = []
    for role, value in items:
        out.extend(flatten(role, value))
    return out



def handleJsonExamples(items):
    """
    Handle roles for OpenAI APIs, converting items to JSON message format.
    Accepts a list of (role, value) tuples, where value can be:
        - str: will be wrapped using handleJsonFormat
        - dict: added as-is
        - list of dicts: each dict is added individually
    Returns a flat list of message dicts.
    """
    # out = []
    # for role, value in items:
    #     if isinstance(value, str):
    #         out.append(handleJsonFormat(role, value))
    #     elif isinstance(value, dict):
    #         out.append(value)
    #     elif isinstance(value, list) and all(isinstance(i, dict) for i in value):
    #         out.extend(value)
    #     elif value is not None:
    #         raise ValueError(f"{role.title()} must be a string, dict, or a list of dicts.")
    # return out
    return handleExamples(items, handleJsonFormat)


def handleTypedExamples(items):
    """
    Handle roles for Google GenAI APIs, converting items to Gemini Content/Part types.
    Accepts a list of (role, value) tuples, where value can be:
        - str: will be wrapped using handleTypedFormat
        - dict: wrapped as Content with role, value as text
        - list of dicts: each dict converted to Content with role, dict as text
    Returns a flat list of Content objects.
    """
    # out = []
    # for role, value in items:
    #     if isinstance(value, str):
    #         out.append(handleTypedFormat(role, value))
    #     elif isinstance(value, dict):
    #         out.append(value)
    #     elif isinstance(value, list) and all(isinstance(i, dict) for i in value):
    #         out.extend(value)
    #     elif value is not None:
    #         raise ValueError(f"{role.title()} must be a string, dict, or a list of dicts.")
    # return out
    return handleExamples(items, handleTypedFormat)


formatExamples = handleExamples
formatTypedExamples = handleTypedExamples
formatJsonExamples = handleJsonExamples
