from typing import Any

from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict

from snakestack.logging.enumerators import LogFilters, LogFormatter


class LoggingSettings(BaseSettings):
    model_config = SettingsConfigDict(env_prefix="SNAKESTACK_LOGGING_")

    level: str = Field(
        default="INFO",
        description="Logging level for the application (e.g., DEBUG, INFO, WARNING, ERROR)."
    )

    name: str = Field(
        default="__main__",
        description="Name of the application (e.g., snakestack)."
    )

    lib_level: str = Field(
        default="WARNING",
        description="Logging level for the third libraries (e.g., INFO, WARNING, ERROR)."
    )

    formatter: str = Field(
        default="default",
        description="Default formatter to be used in the logging configuration (e.g., default, json, with_request_id)."
    )

    filters: list[str] | str  = Field(
        default="request_id",
        description="Comma-separated list of default filters to be applied to log records (e.g., request_id, excluded_name, filter_paths)."
    )

    filter_excluded_name: list[str] | None = Field(
        default=None,
        description="Logger name or pattern to exclude from logging output (e.g., 'exclude.me' to suppress logs from that logger)."
    )

    filter_paths: list[str] | None = Field(
        default=None,
        description="Comma-separated list of paths to filter log records (e.g., '/healthcheck' to suppress logs)."
    )

    @field_validator("formatter")
    @classmethod
    def validate_log_formatter(cls, v: str) -> str:
        allowed = [str(member.value) for member in LogFormatter]
        if v not in allowed:
            raise ValueError(f"Invalid formatter '{v}'. Must be one of: {', '.join(allowed)}.")
        return v

    @field_validator("filters")
    @classmethod
    def validate_log_filter(cls, v: str) -> list[str]:
        allowed = [str(member.value) for member in LogFilters]

        if isinstance(v, list):
            if not all([item in allowed for item in v]):
                raise ValueError(f"Invalid filter '{v}'. Must be one of: {', '.join(allowed)}.")
            return v

        if not all ([item.strip() in allowed for item in v.split(",")]):
            raise ValueError(f"Invalid filter '{v}'. Must be one of {', '.join(allowed)}.")

        return v.split(",")

    @field_validator("filter_excluded_name", mode="before")
    @classmethod
    def convert_filter_excluded_name(cls, v: Any) -> list[str]:
        if not isinstance(v, str):
            return []

        parts = [p.strip() for p in v.split(",") if v.split()]
        return [p for p in parts if p]

    @field_validator("filter_paths", mode="before")
    @classmethod
    def convert_filter_paths(cls, v: Any) -> list[str]:
        if not isinstance(v, str):
            return []

        parts = [p.strip() for p in v.split(",") if v.split()]
        return [p for p in parts if p]

    @field_validator("level", "lib_level")
    @classmethod
    def validate_log_level(cls, v: str) -> str:
        allowed = {"CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "NOTSET"}
        value = v.upper().strip()
        if value not in allowed:
            raise ValueError(f"Invalid log level '{v}'. Must be one of {', '.join(allowed)}.")
        return value
