from typing import Generator, Dict, List, Self, Optional, AsyncGenerator

from alayaflow.utils.singleton import SingletonMeta
from alayaflow.workflow import WorkflowManager
from alayaflow.execution import ExecutorManager, ExecutorType
from alayaflow.common.config import settings
from alayaflow.component.model import ModelManager, ModelProfile
from alayaflow.workflow.runnable import BaseRunnableWorkflow
from alayaflow.utils.logger import AlayaFlowLogger


logger = AlayaFlowLogger()


class APISingleton(metaclass=SingletonMeta):
    def __init__(self) -> None:
        self.workflow_manager = WorkflowManager()
        self.executor_manager = ExecutorManager(
            workflow_manager=self.workflow_manager
        )
        self.model_manager = ModelManager()
        self._inited = False                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

    def is_inited(self) -> bool:
        return self._inited

    def _check_init(self) -> None:
        if not self._inited:
            raise ValueError("Flow APISingleton is not initialized. Please call init() first.")

    def init(self, config: dict = None) -> Self:
        """初始化 Flow APISingleton"""
        if self._inited:
            logger.warning("Flow APISingleton is already initialized. Will override the existing config.")

        if config:
            for key, value in config.items():
                if hasattr(settings, key):
                    setattr(settings, key, value)       # will be check by pydantic validator
                else:
                    logger.warning(f"Config key '{key}' is not a valid setting field. Ignored.")

        logger.info(f"AlayaFlow is initialized with config: {settings.model_dump()}")
        
        self._inited = True
        return self

    def list_registered_models(self) -> List[ModelProfile]:
        """列举已注册的模型"""
        self._check_init()
        return self.model_manager.list_registered_models()

    def register_models(self, model_profiles: List[dict | ModelProfile], overwrite: bool = False) -> None:
        self._check_init()
        profiles = [ModelProfile(**profile) if isinstance(profile, dict) else profile for profile in model_profiles]
        for profile in profiles:
            self.model_manager.register_profile(profile, overwrite=overwrite)

    def list_loaded_workflows(self) -> List[str]:
        """列举已加载的工作流"""
        self._check_init()
        return self.workflow_manager.list_loaded_workflows()

    def list_local_workflows(self) -> List[str]:
        """列举本地已安装的工作流"""
        self._check_init()
        return self.workflow_manager.list_local_workflows()

    def list_remote_workflows(self) -> List[str]:
        """列举远程未安装的工作流"""
        self._check_init()
        return self.workflow_manager.list_remote_workflows()

    def list_all_workflows(self) -> Dict[str, List[str]]:
        """列举工作流，分别返回本地已安装和远程未安装的工作流"""
        self._check_init()
        return self.workflow_manager.list_all_workflows()

    def get_workflow_info(self, workflow_id: str, version: str) -> dict:
        """获取工作流信息"""
        self._check_init()
        return self.workflow_manager.get_workflow_info(workflow_id, version).to_dict()

    def install_workflow(self, workflow_id: str, version: str, force_reinstall: bool = False) -> bool:
        """安装工作流"""
        self._check_init()
        return self.workflow_manager.install_workflow(workflow_id, version, force_reinstall)

    def uninstall_workflow(self, workflow_id: str) -> bool:
        """卸载工作流"""
        self._check_init()
        return self.workflow_manager.uninstall_workflow(workflow_id)

    def load_workflow(self, workflow_id: str, version: str, init_args: Optional[Dict] = None, workflow_dir: Optional[str] = None) -> None:
        """加载本地工作流"""
        self._check_init()
        return self.workflow_manager.load_workflow(workflow_id, version, init_args or {}, workflow_dir)

    def register_workflow(self, runnable: BaseRunnableWorkflow, requirements: List[str] = None) -> None:
        """加载Python项目中的工作流"""
        self._check_init()
        self.workflow_manager.register_workflow(runnable, requirements or [])

    def install_then_load_workflow(self, workflow_id: str, version: str, init_args: Optional[Dict] = None, force_reinstall: bool = False, workflow_dir: Optional[str] = None) -> None:
        """安装并加载工作流"""
        self._check_init()
        self.workflow_manager.install_workflow(workflow_id, version, force_reinstall, workflow_dir)
        self.workflow_manager.load_workflow(workflow_id, version, init_args or {}, workflow_dir)

    def exec_workflow(
        self,
        workflow_id: str,
        version: str,
        inputs: dict,
        context: dict,
        executor_type: str | ExecutorType = ExecutorType.NAIVE,
        metadata: dict = None
    ) -> Generator[dict, None, None]:
        """执行工作流"""
        self._check_init()
        for event in self.executor_manager.exec_workflow(
            workflow_id=workflow_id,
            version=version,
            inputs=inputs,
            context=context,
            executor_type=executor_type,
            metadata=metadata
        ):
            yield event

    async def exec_workflow_async(
        self,
        workflow_id: str,
        version: str,
        inputs: dict,
        context: dict,
        executor_type: str | ExecutorType = ExecutorType.NAIVE,
        metadata: dict = None
    ) -> AsyncGenerator[dict, None]:
        """异步执行工作流"""
        self._check_init()
        async for event in self.executor_manager.exec_workflow_async(
            workflow_id=workflow_id,
            version=version,
            inputs=inputs,
            context=context,
            executor_type=executor_type,
            metadata=metadata
        ):
            yield event
