from __future__ import annotations

import inspect
from enum import Enum

from amsdal_models.classes.model import Model
from amsdal_utils.models.data_models.reference import Reference
from pydantic import BaseModel


class SerializeMode(str, Enum):
    PAYLOAD = 'payload'
    PROMPT = 'prompt'
    DIFF = 'diff'


def normalize_value_for_diff(value: object) -> object:
    if isinstance(value, Reference):
        ref = value.ref
        if isinstance(ref, str):
            return ref
        if isinstance(ref, dict):
            object_id = ref.get('object_id')
            return str(object_id) if object_id is not None else None

        object_id = getattr(ref, 'object_id', None)
        return str(object_id) if object_id is not None else None

    if isinstance(value, Model):
        return str(value.object_id)

    if isinstance(value, BaseModel):
        return value.model_dump()

    return value


async def serialize_model(
    target: Model,
    *,
    mode: SerializeMode,
    model_class: type[Model] | None = None,
) -> dict[str, object]:
    cls = model_class or target.__class__
    model_fields = cls.model_fields

    data: dict[str, object] = {}

    for field_name in model_fields:
        value = getattr(target, field_name)
        if inspect.isawaitable(value):
            value = await value

        if mode == SerializeMode.DIFF:
            data[field_name] = normalize_value_for_diff(value)
            continue

        if mode == SerializeMode.PROMPT:
            if isinstance(value, Model):
                display_name = value.display_name
                if inspect.isawaitable(display_name):
                    display_name = await display_name
                data[field_name] = display_name
                continue

            if isinstance(value, BaseModel):
                data[field_name] = value.model_dump()
                continue

            data[field_name] = value
            continue

        if mode == SerializeMode.PAYLOAD:
            if isinstance(value, BaseModel) and not isinstance(value, Model):
                data[field_name] = value.model_dump()
            else:
                data[field_name] = value
            continue

        msg = f'Unsupported serialization mode: {mode}'
        raise ValueError(msg)

    return data
