"""
nokrashi - Code quality checks and test analysis toolkit for Python projects.

Provides:
- TestSuite: Unified interface for pytest-based code quality checks
- analyze_project: Run all analysis tools and return prioritized findings
- GrafanaIntegration: Optional dashboard validation

Usage:
    from nokrashi import TestSuite
    from pathlib import Path

    # Basic checks (no Grafana)
    suite = TestSuite(project_root=Path("."))

    # With Grafana integration
    suite = TestSuite(
        project_root=Path("."),
        grafana_dashboard_uid="my-dashboard",
        grafana_url="https://grafana.example.com",
    )

    class TestMyProject(suite.create_test_class()):
        pass

    # Project analysis:
    from nokrashi import analyze_project
    report = analyze_project("/path/to/project")
"""

from dataclasses import dataclass, field
from pathlib import Path

# Import primary analysis API (submodules available as nokrashi.analysis.*)
from .analysis import AnalysisConfig, AnalysisReport, analyze_project
# Import check modules
from .checks import (CheckBase, ConfigChecks, FormattingChecks, ImportChecks,
                     LoggingChecks, SafetyChecks, SchemaChecks, StyleChecks)
# Import other modules
from .grafana_integration import GrafanaIntegration


@dataclass
class TestSuite:
    """Unified interface for all code quality checks.

    All configuration is passed explicitly. Only `project_root` is required.
    Grafana integration is optional — checks are skipped if not configured.

    Attributes:
        project_root: Path to project root directory
        grafana_dashboard_uid: Dashboard UID to validate (optional)
        grafana_url: Grafana base URL (optional)
        grafana_metrics_interval: How often metrics are pushed, in seconds
        grafana_api_token: API token for Grafana
        config_file: File allowed to import dotenv (default: "config.py")
        test_dir: Test directory, excluded from some checks (default: "tests")
        skip_tests: Set of test names to skip
        skip_dirs: Directories to exclude from scanning
    """

    __test__ = False  # Prevent pytest collection

    project_root: Path

    # Grafana config — explicit, no singleton
    grafana_dashboard_uid: str = ""
    grafana_url: str = ""
    grafana_metrics_interval: int = 15
    grafana_api_token: str | None = None

    # Common configuration
    config_file: str = "config.py"
    test_dir: str = "tests"
    skip_tests: set[str] = field(default_factory=set)
    skip_dirs: set[str] = field(
        default_factory=lambda: {
            ".git",
            "venv",
            ".venv",
            "__pycache__",
            ".pytest_cache",
            "node_modules",
        }
    )

    # Import checks config
    unencapsulated_packages: set[str] = field(default_factory=set)
    infra_env_vars: set[str] = field(
        default_factory=lambda: {
            "DATABASE_URL",
            "KAFKA_BOOTSTRAP_SERVERS",
            "GRAFANA_URL",
            "LOKI_URL",
            "MIMIR_URL",
            "REDIS_URL",
        }
    )

    # Config checks config
    additional_required_env_vars: set[str] = field(default_factory=set)
    required_gitignore_entries: set[str] = field(
        default_factory=lambda: {
            "__pycache__/",
            "*.py[cod]",
            "*$py.class",
            "*.so",
            ".Python",
            "venv/",
            ".venv/",
            "env/",
            "ENV/",
            ".vscode/",
            ".idea/",
            "*.swp",
            "*.swo",
            ".env",
            "*.bak",
            ".pytest_cache/",
            ".coverage",
            "htmlcov/",
            "*.log",
            ".DS_Store",
            "Thumbs.db",
            "node_modules/",
        }
    )

    # Schema checks config
    sqlalchemy_models: list[str] = field(default_factory=list)

    def __post_init__(self) -> None:
        """Initialize check modules with shared configuration."""
        base_kwargs = {
            "project_root": self.project_root,
            "test_dir": self.test_dir,
            "skip_tests": self.skip_tests,
            "skip_dirs": self.skip_dirs,
        }

        self._formatting = FormattingChecks(**base_kwargs)

        self._imports = ImportChecks(
            **base_kwargs,
            config_file=self.config_file,
            infra_env_vars=self.infra_env_vars,
            unencapsulated_packages=self.unencapsulated_packages,
        )

        self._logging = LoggingChecks(**base_kwargs)

        self._config = ConfigChecks(
            **base_kwargs,
            config_file=self.config_file,
            infra_env_vars=self.infra_env_vars,
            additional_required_env_vars=self.additional_required_env_vars,
            required_gitignore_entries=self.required_gitignore_entries,
        )

        self._style = StyleChecks(
            **base_kwargs,
            config_file=self.config_file,
        )

        self._safety = SafetyChecks(**base_kwargs)

        self._schema = SchemaChecks(
            **base_kwargs,
            sqlalchemy_models=self.sqlalchemy_models,
        )

        self._grafana = None
        if self.grafana_dashboard_uid and self.grafana_url:
            self._grafana = GrafanaIntegration(
                grafana_url=self.grafana_url,
                dashboard_uid=self.grafana_dashboard_uid,
                metrics_interval_seconds=self.grafana_metrics_interval,
                api_token=self.grafana_api_token,
                skip_tests=self.skip_tests,
            )

    @property
    def formatting(self) -> FormattingChecks:
        """Black and isort validation."""
        return self._formatting

    @property
    def imports(self) -> ImportChecks:
        """Import pattern and encapsulation validation."""
        return self._imports

    @property
    def logging(self) -> LoggingChecks:
        """Logging pattern validation."""
        return self._logging

    @property
    def config(self) -> ConfigChecks:
        """Configuration and environment validation."""
        return self._config

    @property
    def style(self) -> StyleChecks:
        """Code style validation."""
        return self._style

    @property
    def safety(self) -> SafetyChecks:
        """Code safety validation."""
        return self._safety

    @property
    def schema(self) -> SchemaChecks:
        """Database schema validation."""
        return self._schema

    @property
    def grafana(self) -> GrafanaIntegration | None:
        """Grafana dashboard validation (None if not configured)."""
        return self._grafana

    def create_test_class(self):
        """Create a combined test class with all checks.

        Returns a class that includes tests from all check modules.
        Individual check modules can also be used directly for more
        granular control. Grafana tests are only included if configured.
        """
        suite = self

        bases = [
            suite.formatting.create_test_class(),
            suite.imports.create_test_class(),
            suite.logging.create_test_class(),
            suite.config.create_test_class(),
            suite.style.create_test_class(),
            suite.safety.create_test_class(),
            suite.schema.create_test_class(),
        ]

        if suite.grafana:
            bases.append(suite.grafana.create_test_class())

        class CombinedTests(*bases):
            """Combined test class with all code quality checks."""

            pass

        return CombinedTests


__all__ = [
    # Primary API
    "TestSuite",
    "analyze_project",
    "AnalysisConfig",
    "AnalysisReport",
    # Check modules (for granular use)
    "CheckBase",
    "FormattingChecks",
    "ImportChecks",
    "LoggingChecks",
    "ConfigChecks",
    "StyleChecks",
    "SafetyChecks",
    "SchemaChecks",
    "GrafanaIntegration",
]
