from dataclasses import dataclass
from functools import cached_property
from os import getenv
from pathlib import Path
from urllib.parse import quote_plus

from csirtmu.core.dataclass_config_loader import load_dataclass_config
from csirtmu.core.logging import LoggingConfig
from csirtmu.core.temporal import TemporalConfig as BaseTemporalConfig

BASE_DIR = Path(__file__).parent.parent.parent
ENV_PREFIX = "CSIRTMU_BETA_WORKER"


@dataclass
class TemporalConfig(BaseTemporalConfig):
    beta_tasks_queue: str = "beta-tasks-queue"
    periodic_tasks_queue: str = "periodic-workflows"
    allow_internal_cancels: bool = False
    child_workflow_timeout: int = 300


@dataclass
class MattermostConfig:
    host: str
    username: str | None
    password: str | None
    webhook: str


@dataclass
class RTConfig:
    base_url: str
    ignored_users: list[str]
    token: str | None
    verify_cert: bool = True

    @property
    def host(self) -> str:
        return self.base_url + ("" if self.base_url.endswith("/") else "/") + "REST/2.0/"


@dataclass
class PeriodicTicketOpenerConfig:
    interval_hours: int
    queues: list[str]


@dataclass
class TransactionRetentionConfig:
    use_jetstream: bool = False
    retry_workflow_interval_minutes: int = 10
    store_failed_transactions: bool = True
    mm_channel: str = "mmrttestchannel"


@dataclass(unsafe_hash=True)
class NetboxConfig:
    url: str
    token: str
    force_ipv4_only: bool = False
    timeout: float = 10.0
    cache_ttl: int = 300
    cache_details_ttl: int = 3600

    @property
    def auth_headers(self) -> dict[str, str]:
        return {"Authorization": f"Token {self.token}"}

    @cached_property
    def base_url(self) -> str:
        return self.url.rstrip("/")

    @property
    def graphql_url(self) -> str:
        url_ = self.url
        url_ = url_.removesuffix("/")  # pragma: no cover
        return url_ if url_.endswith("/graphql") else f"{url_}/graphql/"


@dataclass
class AlphaConfig:
    url: str
    token: str
    force_ipv4_only: bool = False
    timeout: float = 10.0

    @property
    def auth_headers(self) -> dict[str, str]:
        return {"Authorization": f"Token {self.token}"}


@dataclass
class DataPlatformTrinoConfig:
    host: str
    port: int
    catalog: str
    schema: str
    username: str
    password: str

    @property
    def url(self) -> str:
        return (
            f"trino://{self.username}:{quote_plus(self.password)}@{self.host}:{self.port}/{self.catalog}/{self.schema}"
        )


@dataclass
class RedisConfig:
    host: str
    username: str | None = None
    password: str | None = None
    port: int = 6379


@dataclass
class MonitoringConfig:
    dsn: str
    traces_sample_rate: float = 1.0
    profiles_sample_rate: float = 1.0


@dataclass
class GitlabConfig:
    url: str
    token: str
    project_id: int
    assignee_ids: list[int]
    service_account_id: int
    labels: list[str]


@dataclass
class Config:
    mattermost: MattermostConfig
    rt: RTConfig
    temporal: TemporalConfig
    logging: LoggingConfig
    allow_metrics: bool
    metrics_port: int
    periodic_workflow_config: PeriodicTicketOpenerConfig
    netbox: NetboxConfig
    alpha: AlphaConfig
    data_platform: DataPlatformTrinoConfig
    redis: RedisConfig
    gitlab: GitlabConfig
    transaction_retention: TransactionRetentionConfig
    monitoring: MonitoringConfig | None = None


class AppConfig:
    _config: Config | None = None

    @classmethod
    def get(cls, config_path: Path | None = None) -> Config:
        if cls._config is None:
            if config_path is None:  # pragma: no cover
                config_path = Path(
                    getenv(f"{ENV_PREFIX}_CONFIG_PATH", (BASE_DIR / "config/worker_config.yaml").resolve())
                )
            cls._config = load_dataclass_config(config_path, Config, ENV_PREFIX)
        return cls._config
