"""
API Client
"""
import argparse
import json
import os
import platform

from termcolor import colored

from paddlehelix import Configuration, ApiClient
from paddlehelix.api.config import SCHEME, HOST, BALANCE_HOST
from paddlehelix.api.helixfold3_api import Helixfold3Api
from paddlehelix.api.task_api import TaskApi
from paddlehelix.api.bce_api import BceApi
from paddlehelix.utils.logger import create_logger


def get_config_file_path():
    """Returns the path to the configuration file."""
    system_name = platform.system()

    if system_name == "Windows":
        # Windows: 使用 AppData 目录
        config_dir = os.path.join(os.getenv('APPDATA'), "PaddleHelix")
    else:
        # Linux / macOS: 使用用户主目录下的 .config 目录
        config_dir = os.path.join(os.path.expanduser("~"), ".config", "PaddleHelix")

    os.makedirs(config_dir, exist_ok=True)

    config_file = os.path.join(config_dir, "config.json")
    return config_file

def load_config(config_file):
    """Loads AK and SK from the configuration file."""

    if os.path.exists(config_file):
        with open(config_file, "r") as file:
            config = json.load(file)
        return config.get("PADDLEHELIX_API_AK"), config.get("PADDLEHELIX_API_SK")
    return None, None

def save_config(ak, sk, config_file, logger=None):
    """Saves AK and SK to the configuration file."""
    conf_ak, conf_sk = load_config(config_file)
    if conf_ak and conf_sk:
        # 检查配置文件和env vars的AKSK是否一致，如果不一致警告用户
        if conf_ak != ak or conf_sk != sk:
            if logger:
                logger.warning(colored(f"The PaddleHelix API Access Key and Secret Key in the configuration file ({config_file}) are different from the provided AKSK.", 'red'))
                logger.warning(colored(f"Will use provided AKSK update the configuration file!", 'red'))

    config = {
        "PADDLEHELIX_API_AK": ak,
        "PADDLEHELIX_API_SK": sk
    }

    if logger:
        logger.info(f'Updating the configuration file with provided AKSK: {config_file}.')
    with open(config_file, "w") as file:
        json.dump(config, file, indent=4)


def get_ak_sk_from_envs():
    """Gets AK and SK from environment variables."""
    return os.getenv("PADDLEHELIX_API_AK"), os.getenv("PADDLEHELIX_API_SK")


class APIClientSingleton:
    """Singleton API client class to ensure only one instance exists."""
    _instance = None
    
    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._initialized = False
        return cls._instance
    
    def __init__(self, ak=None, sk=None):
        if not self._initialized:
            self._initialize_clients(ak, sk)
            self._initialized = True
    
    def _initialize_clients(self, ak=None, sk=None):
        """Initialize all client instances."""
        logger = create_logger(name='client')
        config_file_path = get_config_file_path()

        if ak and sk:
            # 通过命令行参数提供AKSK是最高优先级
            logger.info("PaddleHelix API Access Key and Secret Key provided by command line arguments.")
            save_config(ak, sk, config_file_path, logger)
            _ak, _sk = get_ak_sk_from_envs()
            if _ak and _sk and (ak != _ak or sk != _sk):
                logger.error(colored(f"The PaddleHelix API Access Key and Secret Key in the environment variables are different from the provided AKSK.", 'red'))
                logger.error(colored(f"Please unset the environment variables by: 'unset PADDLEHELIX_API_AK && unset PADDLEHELIX_API_SK' and try again!", 'red'))
                exit(1)
            self._create_client_instances(ak, sk)
            return
        
        _ak, _sk = get_ak_sk_from_envs()
        if _ak and _sk:
            # AKSK found in env vars, save to config file
            logger.info("PaddleHelix API Access Key and Secret Key have been successfully loaded from the environment variables.")
            save_config(_ak, _sk, config_file_path, logger)
            self._create_client_instances(_ak, _sk)
            return

        logger.info(
            f"Attempting to load from configuration file: {config_file_path}.")
        _ak, _sk = load_config(config_file_path)
        if _ak and _sk:
            logger.info(f"PaddleHelix API Access Key and Secret Key have been successfully loaded from the configuration file: {config_file_path}.")
            self._create_client_instances(_ak, _sk)
            return

    
    def _create_client_instances(self, ak, sk):
        """Create configurations and initialize all client instances.
        
        Args:
            ak (str): Access Key
            sk (str): Secret Key
        """
        # Create configurations
        paddlehelix_configuration = Configuration(
            host="".join([SCHEME, HOST]),
            api_key={
                'access key': ak,
                'secret key': sk
            }
        )

        balance_configuration = Configuration(
            host="".join([SCHEME, BALANCE_HOST]),
            api_key={
                'access key': ak,
                'secret key': sk
            }
        )
        
        # Create API clients
        helixfold3_client = ApiClient(paddlehelix_configuration)
        task_client = ApiClient(paddlehelix_configuration)
        balance_client = ApiClient(balance_configuration)

        # Initialize client instances
        self.balance_client_instance = BceApi(balance_client)
        self.helixfold3_client_instance = Helixfold3Api(helixfold3_client)
        self.task_client_instance = TaskApi(task_client)


def get_client(ak=None, sk=None):
    """Gets the API client using singleton pattern.

    Attempts to obtain Access Key (AK) and Secret Key (SK) in the following order:
    1. Check env vars，if in env vars, save to config file
    2. If not found in env vars, tries loading from config file
    3. If not found in config file, prompts user for manual input

    Note: This function now uses a singleton pattern to ensure only one client instance
    exists throughout the application lifecycle, improving performance and resource usage.

    Args:
        ak (str, optional): Access Key. Defaults to default test credentials.
        sk (str, optional): Secret Key. Defaults to default test credentials.

    Returns:
        APIClientSingleton: Singleton API client instance.
    """
    # Return singleton instance
    return APIClientSingleton(ak, sk)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='PaddleHelix API 客户端')
    parser.add_argument('--ak', type=str, help='PaddleHelix API Access Key')
    parser.add_argument('--sk', type=str, help='PaddleHelix API Secret Key')
    args = parser.parse_args()

    client = get_client(args.ak, args.sk)