from functools import lru_cache
import json
from typing import Any

from pydantic import SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict
from sqlalchemy.engine import URL


class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        env_ignore_empty=True,
        extra="ignore",
    )

    app_name: str = "NEO ERP Sales API"
    app_env: str = "development"
    app_debug: bool = False
    enable_write_api: bool = False
    enable_customer_write_api: bool = False
    enable_order_write_api: bool = False
    auth_enabled: bool = False
    auth_api_keys_json: SecretStr = SecretStr("{}")
    jwt_secret_key: SecretStr = SecretStr("neoerp-sales-api-secret-key-change-in-production")
    jwt_algorithm: str = "HS256"
    jwt_expires_minutes: int = 1440
    trusted_hosts: str = "localhost,127.0.0.1,testserver,test"
    log_level: str = "INFO"

    db_host: str = "127.0.0.1"
    db_port: int = 3306
    db_user: str
    db_password: SecretStr
    db_name: str
    db_pool_size: int = 5
    db_max_overflow: int = 10
    test_db_name: str | None = None
    test_db_host: str | None = None
    test_db_port: int | None = None
    test_db_user: str | None = None
    test_db_password: SecretStr | None = None

    @property
    def database_url(self) -> URL:
        return URL.create(
            drivername="mysql+asyncmy",
            username=self.db_user,
            password=self.db_password.get_secret_value(),
            host=self.db_host,
            port=self.db_port,
            database=self.db_name,
            query={"charset": "utf8mb4"},
        )

    @property
    def auth_api_keys(self) -> dict[str, dict[str, Any]]:
        value = json.loads(self.auth_api_keys_json.get_secret_value())
        if not isinstance(value, dict):
            raise ValueError("AUTH_API_KEYS_JSON harus berupa object JSON")
        return value

    @property
    def trusted_host_list(self) -> list[str]:
        return [host.strip() for host in self.trusted_hosts.split(",") if host.strip()]

    def validate_runtime(self) -> None:
        if self.app_env.lower() != "production":
            return
        if self.app_debug:
            raise ValueError("APP_DEBUG harus false pada production")
        if not self.auth_enabled:
            raise ValueError("AUTH_ENABLED harus true pada production")
        if not self.auth_api_keys:
            raise ValueError("AUTH_API_KEYS_JSON wajib diisi pada production")
        if "*" in self.trusted_host_list:
            raise ValueError("TRUSTED_HOSTS production tidak boleh berisi *")


@lru_cache
def get_settings() -> Settings:
    return Settings()
