import json
import os
import threading
from dataclasses import dataclass
from typing import Dict, Any, Optional

from pilot.generater.azureopenai import AzureOpenAIAISingleton
from pilot.generater.openai import OpenAIAISingleton
from pilot.generater.generation_config import GenerationConfigDTO
from pilot.generater.lmstudioai import lmstudioAISingleton
from pilot.generater.vectorengineai import VectorEngineAISingleton
from pilot.generater.ai_base import AIBase
from pilot.generater.mattermostai import MattermostAISingleton
from pilot.generater.robinui import RobinAISingleton


@dataclass
class AIConfigDTO:
    veraApi: str
    veraModel: str
    veraUrl: str
    timeOut: int

class VeraSingleton:
    _instance: Optional['VeraSingleton'] = None
    _lock = threading.Lock()

    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super(VeraSingleton, cls).__new__(cls)
                    cls._instance._initialized = False
        return cls._instance

    def __init__(self):
        if not self._initialized:
            with self._lock:

                cwd = os.getcwd()
                filepath = os.path.join(cwd, 'config', 'vera.json')
                
                with open(filepath, 'r', encoding='utf-8') as f:
                    self.config_data = json.load(f)
                
                self.config_dto = self.create_ai_dto()
                self.veraApi = self.config_dto.veraApi
                self.model_name = self.config_dto.veraModel
                self.base_url = self.config_dto.veraUrl
                self.timeout = self.config_dto.timeOut
                self.ai_instance: AIBase  = self.get_ai_instance()
                self._initialized = True

    def get_ai_instance(self) -> Any:
        match self.veraApi:
            case "mattermost":
                return MattermostAISingleton.get_instance(
                    model_name=self.model_name,
                    base_url=self.base_url
                )
            case "lmstudio":
                return lmstudioAISingleton.get_instance(model_name=self.model_name, base_url=self.base_url)
            case "vector":
                return VectorEngineAISingleton.get_instance(model_name=self.model_name, base_url=self.base_url)
            case "azure":
                return AzureOpenAIAISingleton.get_instance(
                    deployment_name=self.model_name,
                    endpoint_url=self.base_url
                )
            case "robin":
                return RobinAISingleton.get_instance(model_name=self.model_name, base_url=self.base_url)
            case "openai" | "deepseek" | "qwen":
                return OpenAIAISingleton.get_instance(model_name=self.model_name, base_url=self.base_url)
            case "ollama" | "gemini" | "openwebui":
                # これらは現在 AIBase を返却（必要に応じて各Singletonへ差し替え）
                return AIBase()

        return AIBase()

    def generate_content(
            self,
            prompt: str,
            gen_config: Optional[GenerationConfigDTO] = None,
            stream: Optional[bool] = None,
            base_url: Optional[str] = None,
            model: Optional[str] = None,
            **kwargs
    ) -> Dict[str, Any]:
        """
        统一的对外调用接口。
        如果外部没有指定 gen_config，将默认使用 properties 文件中读取的 timeout 配置。
        """
        if gen_config is None:
            # 自动应用 vera.properties 中的 timeout 配置
            gen_config = GenerationConfigDTO(timeout=self.timeout)

        # 委托给底层的 ai_instance 执行具体的生成逻辑
        return self.ai_instance.generate_content(
            prompt=prompt,
            gen_config=gen_config,
            stream=stream,
            base_url=base_url,
            model=model,
            **kwargs
        )

    @classmethod
    def get_instance(cls) -> 'VeraSingleton':
        return cls()

    def create_ai_dto(self) -> AIConfigDTO:
        main_config = self.config_data.get('main_config', {})
        api_services = self.config_data.get('api_services', {})
        
        vera_api = main_config.get('active_service', '.')
        active_id = main_config.get('active_id', '.')
        time_out = main_config.get('timeout', 600)
        
        vera_model = '.'
        vera_url = '.'
        
        services_list = api_services.get(vera_api, [])
        for svc in services_list:
            if svc.get('id') == active_id:
                vera_model = svc.get('model', '.')
                vera_url = svc.get('base_url', '.')
                break

        return AIConfigDTO(
            veraApi = vera_api,
            veraModel = vera_model,
            veraUrl = vera_url,
            timeOut = time_out
        )