import os
from dataclasses import dataclass
from typing import Optional

from dotenv import load_dotenv

from dv_launcher.services.logging.custom_logger import CustomLogger

logger = CustomLogger()


@dataclass
class Constants:
    COMPOSE_PROJECT_NAME: Optional[str]
    ODOO_VERSION: Optional[str]
    POSTGRES_VERSION: Optional[str]
    ODOO_EXPOSED_PORT: Optional[str]
    ODOO_INTERNAL_PORT: Optional[str]
    ODOO_CONFIG: Optional[str]
    ODOO_ADDONS: Optional[str]
    OPTIONAL_WHISPER: bool
    AUTO_INSTALL_MODULES: bool
    AUTO_UPDATE_MODULES: bool
    UPDATE_MODULE_LIST: Optional[str]
    FORCE_UPDATE: bool
    AUTO_CREATE_DATABASE: bool
    INITIAL_DB_MASTER_PASS: Optional[str]
    INITIAL_DB_NAME: Optional[str]
    INITIAL_DB_USER: Optional[str]
    INITIAL_DB_USER_PASS: Optional[str]
    BASE_DIR: str
    ADDONS_FOLDER: list[str]
    ENV_FILE: str
    DOCKERFILE_FILE: str
    CACHE_FOLDER: str
    CACHE_CONFIG_FILE: str
    CACHE_ADDONS_FILE: str

    @classmethod
    def from_env(cls, cwd: str) -> 'Constants':
        # Load environment variables from .env file
        load_dotenv(f"{cwd}/.env")

        # Load docker-compose.override.yml file and extract addon folders
        addon_folders = set()
        with open(f"{cwd}/docker-compose.override.yml", "r") as f:
            for line in f:
                if line.strip().startswith("-"):
                    line = line.replace("-", "", 1).strip()
                    addon_folders.add(line.split(":")[0].strip())

        return cls(
            COMPOSE_PROJECT_NAME=os.getenv('COMPOSE_PROJECT_NAME'),
            ODOO_VERSION=os.getenv('ODOO_VERSION'),
            POSTGRES_VERSION=os.getenv('POSTGRES_VERSION'),
            ODOO_EXPOSED_PORT=os.getenv('ODOO_EXPOSED_PORT'),
            ODOO_INTERNAL_PORT=os.getenv('ODOO_INTERNAL_PORT'),
            ODOO_CONFIG=os.getenv('ODOO_CONFIG'),
            ODOO_ADDONS=os.getenv('ODOO_ADDONS'),
            OPTIONAL_WHISPER=True if (
                    os.getenv('OPTIONAL_WHISPER') == 'True' or os.getenv('OPTIONAL_WHISPER') == 'true') else False,
            AUTO_INSTALL_MODULES=True if (os.getenv('AUTO_INSTALL_MODULES') == 'True' or os.getenv(
                'AUTO_INSTALL_MODULES') == 'true') else False,
            AUTO_UPDATE_MODULES=True if (os.getenv('AUTO_UPDATE_MODULES') == 'True' or os.getenv(
                'AUTO_UPDATE_MODULES') == 'true') else False,
            UPDATE_MODULE_LIST=os.getenv('UPDATE_MODULE_LIST'),
            FORCE_UPDATE=True if (
                    os.getenv('FORCE_UPDATE') == 'True' or os.getenv('FORCE_UPDATE') == 'true') else False,
            AUTO_CREATE_DATABASE=True if (os.getenv('AUTO_CREATE_DATABASE') == 'True' or os.getenv(
                'AUTO_CREATE_DATABASE') == 'true') else False,
            INITIAL_DB_MASTER_PASS=os.getenv('INITIAL_DB_MASTER_PASS'),
            INITIAL_DB_NAME=os.getenv('INITIAL_DB_NAME'),
            INITIAL_DB_USER=os.getenv('INITIAL_DB_USER'),
            INITIAL_DB_USER_PASS=os.getenv('INITIAL_DB_USER_PASS'),
            BASE_DIR=cwd,
            ADDONS_FOLDER=list(addon_folders),
            ENV_FILE=os.path.join(cwd, ".env"),
            DOCKERFILE_FILE=os.path.join(cwd, "Dockerfile"),
            CACHE_FOLDER=os.path.join(cwd, "cache"),
            CACHE_CONFIG_FILE=os.path.join(cwd, "cache", "config_cache.json"),
            CACHE_ADDONS_FILE=os.path.join(cwd, "cache", "addons_cache.json")
        )

    def __post_init__(self):
        if self.ODOO_VERSION not in ['16', '17', '18', '19']:
            logger.error(f"Invalid ODOO_VERSION: {self.ODOO_VERSION}. Supported versions are 16, 17, 18, 19")
            exit(1)
        for addon_folder in self.ADDONS_FOLDER:
            if not os.path.exists(addon_folder):
                print(addon_folder)
                logger.error(f"Invalid ODOO_ADDONS acho: {addon_folder}. Folder does not exist")
                exit(1)


_instance: Optional[Constants] = None


def get_constants(base_dir: str = None) -> Constants:
    """ Singleton pattern to get the constants """
    global _instance
    if _instance is None:
        if base_dir is None:
            raise ValueError("base_dir must be provided on first call")
        _instance = Constants.from_env(base_dir)
    return _instance
