"""Checkers package - all code quality checkers."""

from __future__ import annotations

from stablestack.checkers.base import BaseChecker

# Security checkers (free tier)
from stablestack.checkers.security import (
    EvalUsageChecker,
    HardcodedSecretsChecker,
    InnerHtmlXssChecker,
    InsecureRandomChecker,
    NodeEnvSecurityGateChecker,
    SqlInjectionChecker,
    WebhookSecurityBypassChecker,
)

# Session checkers (free tier)
from stablestack.checkers.session import ThreadSessionSafetyChecker

# Schema checkers (free tier)
from stablestack.checkers.schema import (
    PydanticNullabilityChecker,
    PydanticSqlalchemyFieldChecker,
)

# Project checkers (free tier)
from stablestack.checkers.project.claude_md import ClaudeMdChecker
from stablestack.checkers.project.gitignored_claude_md import GitignoredClaudeMdChecker

# Quality checkers (free tier)
from stablestack.checkers.quality.exception_swallowing import ExceptionSwallowingChecker
from stablestack.checkers.quality.file_length import FileLengthChecker

# Async checkers (free tier — source has false-positive fixes not in compiled .so)
from stablestack.checkers.async_checks.missing_await import MissingAwaitChecker

# Structure checkers (free tier)
from stablestack.checkers.structure.multiple_classes import MultipleClassesChecker

# Paid checkers that were accidentally included in free tier imports.
# These are loaded via load_paid_checkers() when a license is activated.
# Import them optionally so the free tier wheel still works without them.
try:
    from stablestack.checkers.quality.background_task_tracing import BackgroundTaskTracingChecker
except ImportError:
    BackgroundTaskTracingChecker = None  # type: ignore[assignment,misc]

try:
    from stablestack.checkers.api.untyped_response import UntypedResponseChecker
except ImportError:
    UntypedResponseChecker = None  # type: ignore[assignment,misc]

try:
    from stablestack.checkers.memory.global_state_singleton import GlobalStateSingletonChecker
except ImportError:
    GlobalStateSingletonChecker = None  # type: ignore[assignment,misc]

try:
    from stablestack.checkers.quality.case_insensitive_email import CaseInsensitiveEmailChecker
except ImportError:
    CaseInsensitiveEmailChecker = None  # type: ignore[assignment,misc]

try:
    from stablestack.checkers.types.typescript_any import TypeScriptAnyChecker
except ImportError:
    TypeScriptAnyChecker = None  # type: ignore[assignment,misc]

try:
    from stablestack.checkers.structure.duplicate_client_init import DuplicateClientInitChecker
except ImportError:
    DuplicateClientInitChecker = None  # type: ignore[assignment,misc]


# Free-tier checkers: always available in the PyPI package.
FREE_CHECKERS: list[type[BaseChecker]] = [
    # Security (SEC001-SEC006, SEC012)
    HardcodedSecretsChecker,
    SqlInjectionChecker,
    EvalUsageChecker,
    InsecureRandomChecker,
    InnerHtmlXssChecker,
    WebhookSecurityBypassChecker,
    NodeEnvSecurityGateChecker,
    # Session (SESS002)
    ThreadSessionSafetyChecker,
    # Schema (SCHEMA001-SCHEMA002)
    PydanticNullabilityChecker,
    PydanticSqlalchemyFieldChecker,
    # Project (PROJ001, PROJ005)
    ClaudeMdChecker,
    GitignoredClaudeMdChecker,
    # Quality (QUAL001, QUAL009)
    ExceptionSwallowingChecker,
    FileLengthChecker,
    # Structure (STRUCT001)
    MultipleClassesChecker,
    # Async (ASYNC001)
    MissingAwaitChecker,
]

# Add optional checkers that may not be in the free tier wheel
if BackgroundTaskTracingChecker is not None:
    FREE_CHECKERS.append(BackgroundTaskTracingChecker)
if UntypedResponseChecker is not None:
    FREE_CHECKERS.append(UntypedResponseChecker)
if GlobalStateSingletonChecker is not None:
    FREE_CHECKERS.append(GlobalStateSingletonChecker)
if CaseInsensitiveEmailChecker is not None:
    FREE_CHECKERS.append(CaseInsensitiveEmailChecker)
if TypeScriptAnyChecker is not None:
    FREE_CHECKERS.append(TypeScriptAnyChecker)
if DuplicateClientInitChecker is not None:
    FREE_CHECKERS.append(DuplicateClientInitChecker)


def get_all_checkers() -> list[type[BaseChecker]]:
    """Return free checkers + any paid compiled checkers that are installed.

    Deduplicates by rule_id so checkers that appear in both FREE_CHECKERS
    and the paid compiled bundle are only returned once.  When a compiled
    (paid) version exists for a rule_id, it takes precedence over the
    source stub in FREE_CHECKERS because the compiled bundle is the
    canonical, up-to-date implementation.
    """
    from stablestack.checkers.loader import load_paid_checkers

    paid = load_paid_checkers()
    paid_rule_ids: set[str] = {cls.rule_id for cls in paid}
    # Exclude free-tier stubs that have a newer compiled replacement
    free = [cls for cls in FREE_CHECKERS if cls.rule_id not in paid_rule_ids]
    return free + paid


# Backwards compat: ALL_CHECKERS now delegates to get_all_checkers()
# so code that imported ALL_CHECKERS still works at module level.
ALL_CHECKERS: list[type[BaseChecker]] = FREE_CHECKERS


__all__ = [
    "BaseChecker",
    "ALL_CHECKERS",
    "FREE_CHECKERS",
    "get_all_checkers",
    # Free-tier security checkers
    "HardcodedSecretsChecker",
    "SqlInjectionChecker",
    "EvalUsageChecker",
    "InsecureRandomChecker",
    "InnerHtmlXssChecker",
    "WebhookSecurityBypassChecker",
    "NodeEnvSecurityGateChecker",
    # Free-tier session checkers
    "ThreadSessionSafetyChecker",
    # Free-tier schema checkers
    "PydanticNullabilityChecker",
    "PydanticSqlalchemyFieldChecker",
    # Free-tier project checkers
    "ClaudeMdChecker",
    "GitignoredClaudeMdChecker",
    # Free-tier quality checkers
    "ExceptionSwallowingChecker",
    "FileLengthChecker",
    "BackgroundTaskTracingChecker",
    # Free-tier structure checkers
    "MultipleClassesChecker",
    # Free-tier API checkers
    "UntypedResponseChecker",
    # Free-tier async checkers
    "MissingAwaitChecker",
    # Free-tier memory checkers
    "GlobalStateSingletonChecker",
]
