from typing import Any, Optional

from alayaflow.workflow.workflow_info import WorkflowInfo


class LangfuseTracing:
    def __init__(self, settings: Any) -> None:
        self._settings = settings
        self._client_inited = False

    def _normalize_value(self, value: Optional[str]) -> Optional[str]:
        return value.strip() if isinstance(value, str) and value.strip() else None

    def _merge_tags(self, wf_tags: Optional[list], input_tags: Optional[list]) -> list:
        tags = []
        if isinstance(wf_tags, list):
            tags.extend(wf_tags)
        if isinstance(input_tags, list):
            tags.extend(input_tags)
        if tags:
            # 去重并保持顺序
            seen = set()
            tags = [t for t in tags if not (t in seen or seen.add(t))]
        return tags

    def _init_langfuse_client(self, public_key: str, secret_key: str, host: Optional[str]) -> None:
        if self._client_inited:
            return
        from langfuse import Langfuse
        if host is None:
            Langfuse(public_key=public_key, secret_key=secret_key)
        else:
            Langfuse(public_key=public_key, secret_key=secret_key, host=host)
        self._client_inited = True

    def _load_langfuse_handler_class(self) -> Optional[Any]:
        try:
            from langfuse.langchain import CallbackHandler
            return CallbackHandler
        except Exception:
            try:
                from langfuse.callback import CallbackHandler
                return CallbackHandler
            except Exception:
                return None

    def build_callback(self) -> Optional[Any]:
        if not self._settings.langfuse_enabled:
            return None

        public_key = self._normalize_value(self._settings.langfuse_public_key)
        secret_key = self._normalize_value(self._settings.langfuse_secret_key)
        host = self._normalize_value(self._settings.langfuse_base_url)
        if not (public_key and secret_key):
            return None

        handler_cls = self._load_langfuse_handler_class()
        if handler_cls is None:
            print("[Langfuse] SDK 未安装，跳过追踪。请在工作流 requirements.txt 中添加 langfuse。")
            return None

        try:
            self._init_langfuse_client(public_key, secret_key, host)
            return handler_cls()
        except Exception as e:
            print(f"[Langfuse] 初始化失败，跳过追踪: {e}")
            return None

    def build_config(self, input_data: dict, wf_info: Optional[WorkflowInfo], cb: Any) -> dict:
        metadata = {
            "workflow_id": getattr(wf_info, "id", None) if wf_info is not None else None,
            "workflow_version": getattr(wf_info, "version", None) if wf_info is not None else None,
            "workflow_name": getattr(wf_info, "name", None) if wf_info is not None else None,
        }
        input_metadata = input_data.get("metadata")
        if isinstance(input_metadata, dict):
            metadata.update(input_metadata)

        wf_tags = getattr(wf_info, "tags", None) if wf_info is not None else None
        tags = self._merge_tags(wf_tags, input_data.get("tags"))

        metadata.update({
            "langfuse_user_id": input_data.get("user_id"),
            "langfuse_session_id": input_data.get("session_id"),
            "langfuse_tags": tags or None,
        })
        metadata = {k: v for k, v in metadata.items() if v is not None}

        return {
            "callbacks": [cb],
            "run_name": getattr(wf_info, "name", None) or getattr(wf_info, "id", None),
            "metadata": metadata,
        }


_GLOBAL_TRACING: Optional[LangfuseTracing] = None


def get_tracing(settings: Any) -> LangfuseTracing:
    global _GLOBAL_TRACING
    if _GLOBAL_TRACING is None:
        _GLOBAL_TRACING = LangfuseTracing(settings)
    return _GLOBAL_TRACING

