import dataclasses
import datetime
import json
from typing import Any, cast

from pydantic import BaseModel

from harbory.common.base58 import b58encode
from harbory.common.hashutils import hash_object_bytes
from harbory.common.typeutils import is_namedtuple
from harbory.types import JsonValue


def object_fingerprint(obj: Any) -> str:
    return b58encode(hash_object_bytes(obj)).decode()


def as_jsonvalue(value: Any) -> JsonValue:
    return cast(JsonValue, json.loads(json.dumps(value, cls=WorkflowJSONEncoder)))


class WorkflowJSONEncoder(json.JSONEncoder):
    def default(self, obj: Any) -> Any:
        from .colt import WorkflowRef
        from .graph import WorkflowGraph
        from .step import WorkflowStepInfo

        if isinstance(obj, (WorkflowGraph, WorkflowStepInfo)):
            return obj.to_dict()
        if isinstance(obj, datetime.datetime):
            return obj.isoformat()
        if is_namedtuple(obj):
            return obj._asdict()
        if isinstance(obj, (set, frozenset, tuple)):
            return list(obj)
        if isinstance(obj, WorkflowRef):
            return obj.config
        if dataclasses.is_dataclass(obj) and not isinstance(obj, type):
            return dataclasses.asdict(obj)
        if isinstance(obj, BaseModel):
            return obj.model_dump()
        return super().default(obj)
