"""
Purpose: CLI commands for code pattern linters (improper-logging, method-property, stateless-class, lazy-ignores, lbyl)

Scope: Commands that detect code patterns and anti-patterns in Python code

Overview: Provides CLI commands for code pattern linting: improper-logging detects print() and
    console.log calls that should use proper logging as well as conditional verbose patterns,
    method-property finds methods that should be @property decorators, stateless-class detects
    classes without state that should be module functions, lazy-ignores detects unjustified linting
    suppressions, and lbyl detects Look Before You Leap anti-patterns. Each command supports
    standard options (config, format, recursive) and integrates with the orchestrator for execution.
    Note: print-statements is a deprecated alias for improper-logging.

Dependencies: click for CLI framework, src.cli.main for CLI group, src.cli.utils for shared utilities

Exports: improper_logging, print_statements (alias), method_property, stateless_class, lazy_ignores, lbyl commands

Interfaces: Click CLI commands registered to main CLI group

Implementation: Click decorators for command definition, orchestrator-based linting execution
"""

import sys
from pathlib import Path
from typing import TYPE_CHECKING, NoReturn

from loguru import logger

from src.cli.linters.shared import ExecuteParams, create_linter_command
from src.cli.utils import execute_linting_on_paths, setup_base_orchestrator, validate_paths_exist
from src.core.cli_utils import format_violations
from src.core.types import Violation

if TYPE_CHECKING:
    from src.orchestrator.core import Orchestrator


# =============================================================================
# Improper Logging Command (formerly print-statements)
# =============================================================================


def _setup_improper_logging_orchestrator(
    path_objs: list[Path], config_file: str | None, verbose: bool, project_root: Path | None = None
) -> "Orchestrator":
    """Set up orchestrator for improper-logging command."""
    return setup_base_orchestrator(path_objs, config_file, verbose, project_root)


def _run_improper_logging_lint(
    orchestrator: "Orchestrator", path_objs: list[Path], recursive: bool, parallel: bool = False
) -> list[Violation]:
    """Execute improper-logging lint on files or directories."""
    all_violations = execute_linting_on_paths(orchestrator, path_objs, recursive, parallel)
    return [v for v in all_violations if v.rule_id.startswith("improper-logging.")]


def _execute_improper_logging_lint(params: ExecuteParams) -> NoReturn:
    """Execute improper-logging lint."""
    validate_paths_exist(params.path_objs)
    orchestrator = _setup_improper_logging_orchestrator(
        params.path_objs, params.config_file, params.verbose, params.project_root
    )
    improper_logging_violations = _run_improper_logging_lint(
        orchestrator, params.path_objs, params.recursive, params.parallel
    )

    logger.debug(f"Found {len(improper_logging_violations)} improper logging violation(s)")

    format_violations(improper_logging_violations, params.format)
    sys.exit(1 if improper_logging_violations else 0)


# Primary command
improper_logging = create_linter_command(
    "improper-logging",
    _execute_improper_logging_lint,
    "Check for improper logging patterns in code.",
    "Detects print()/console statements and conditional verbose patterns that should\n"
    "    be replaced with proper logging configuration.",
)

# Backward-compatible alias (deprecated)
print_statements = create_linter_command(
    "print-statements",
    _execute_improper_logging_lint,  # Same executor as improper-logging
    "Alias for improper-logging (deprecated).",
    "DEPRECATED: Use 'improper-logging' instead. Detects print() calls in Python and\n"
    "    console.log/warn/error/debug/info calls in TypeScript/JavaScript.",
)


# =============================================================================
# Method Property Command
# =============================================================================


def _setup_method_property_orchestrator(
    path_objs: list[Path], config_file: str | None, verbose: bool, project_root: Path | None = None
) -> "Orchestrator":
    """Set up orchestrator for method-property command."""
    return setup_base_orchestrator(path_objs, config_file, verbose, project_root)


def _run_method_property_lint(
    orchestrator: "Orchestrator", path_objs: list[Path], recursive: bool, parallel: bool = False
) -> list[Violation]:
    """Execute method-property lint on files or directories."""
    all_violations = execute_linting_on_paths(orchestrator, path_objs, recursive, parallel)
    return [v for v in all_violations if "method-property" in v.rule_id]


def _execute_method_property_lint(params: ExecuteParams) -> NoReturn:
    """Execute method-property lint."""
    validate_paths_exist(params.path_objs)
    orchestrator = _setup_method_property_orchestrator(
        params.path_objs, params.config_file, params.verbose, params.project_root
    )
    method_property_violations = _run_method_property_lint(
        orchestrator, params.path_objs, params.recursive, params.parallel
    )

    logger.debug(f"Found {len(method_property_violations)} method-property violation(s)")

    format_violations(method_property_violations, params.format)
    sys.exit(1 if method_property_violations else 0)


method_property = create_linter_command(
    "method-property",
    _execute_method_property_lint,
    "Check for methods that should be @property decorators.",
    "Detects Python methods that could be converted to properties following\n"
    "    Pythonic conventions: methods returning self._attribute, get_* prefixed\n"
    "    methods (Java-style getters), or simple computed values with no side effects.",
)


# =============================================================================
# Stateless Class Command
# =============================================================================


def _setup_stateless_class_orchestrator(
    path_objs: list[Path], config_file: str | None, verbose: bool, project_root: Path | None = None
) -> "Orchestrator":
    """Set up orchestrator for stateless-class command."""
    return setup_base_orchestrator(path_objs, config_file, verbose, project_root)


def _run_stateless_class_lint(
    orchestrator: "Orchestrator", path_objs: list[Path], recursive: bool, parallel: bool = False
) -> list[Violation]:
    """Execute stateless-class lint on files or directories."""
    all_violations = execute_linting_on_paths(orchestrator, path_objs, recursive, parallel)
    return [v for v in all_violations if "stateless-class" in v.rule_id]


def _execute_stateless_class_lint(params: ExecuteParams) -> NoReturn:
    """Execute stateless-class lint."""
    validate_paths_exist(params.path_objs)
    orchestrator = _setup_stateless_class_orchestrator(
        params.path_objs, params.config_file, params.verbose, params.project_root
    )
    stateless_class_violations = _run_stateless_class_lint(
        orchestrator, params.path_objs, params.recursive, params.parallel
    )

    logger.debug(f"Found {len(stateless_class_violations)} stateless-class violation(s)")

    format_violations(stateless_class_violations, params.format)
    sys.exit(1 if stateless_class_violations else 0)


stateless_class = create_linter_command(
    "stateless-class",
    _execute_stateless_class_lint,
    "Check for stateless classes that should be module functions.",
    "Detects Python classes that have no constructor (__init__), no instance\n"
    "    state, and 2+ methods - indicating they should be refactored to module-level\n"
    "    functions instead of using a class as a namespace.",
)


# =============================================================================
# Lazy Ignores Command
# =============================================================================


def _setup_lazy_ignores_orchestrator(
    path_objs: list[Path], config_file: str | None, verbose: bool, project_root: Path | None = None
) -> "Orchestrator":
    """Set up orchestrator for lazy-ignores command."""
    return setup_base_orchestrator(path_objs, config_file, verbose, project_root)


def _run_lazy_ignores_lint(
    orchestrator: "Orchestrator", path_objs: list[Path], recursive: bool, parallel: bool = False
) -> list[Violation]:
    """Execute lazy-ignores lint on files or directories."""
    all_violations = execute_linting_on_paths(orchestrator, path_objs, recursive, parallel)
    return [v for v in all_violations if v.rule_id.startswith("lazy-ignores")]


def _execute_lazy_ignores_lint(params: ExecuteParams) -> NoReturn:
    """Execute lazy-ignores lint."""
    validate_paths_exist(params.path_objs)
    orchestrator = _setup_lazy_ignores_orchestrator(
        params.path_objs, params.config_file, params.verbose, params.project_root
    )
    lazy_ignores_violations = _run_lazy_ignores_lint(
        orchestrator, params.path_objs, params.recursive, params.parallel
    )

    logger.debug(f"Found {len(lazy_ignores_violations)} lazy-ignores violation(s)")

    format_violations(lazy_ignores_violations, params.format)
    sys.exit(1 if lazy_ignores_violations else 0)


lazy_ignores = create_linter_command(
    "lazy-ignores",
    _execute_lazy_ignores_lint,
    "Check for unjustified linting suppressions.",
    "Detects ignore directives (noqa, type:ignore, pylint:disable, nosec) that lack\n"
    "    corresponding entries in the file header's Suppressions section. Enforces a\n"
    "    header-based suppression model requiring human approval for all linting bypasses.",
)


# =============================================================================
# LBYL Command
# =============================================================================


def _setup_lbyl_orchestrator(
    path_objs: list[Path], config_file: str | None, verbose: bool, project_root: Path | None = None
) -> "Orchestrator":
    """Set up orchestrator for lbyl command."""
    return setup_base_orchestrator(path_objs, config_file, verbose, project_root)


def _run_lbyl_lint(
    orchestrator: "Orchestrator", path_objs: list[Path], recursive: bool, parallel: bool = False
) -> list[Violation]:
    """Execute lbyl lint on files or directories."""
    all_violations = execute_linting_on_paths(orchestrator, path_objs, recursive, parallel)
    return [v for v in all_violations if v.rule_id.startswith("lbyl")]


def _execute_lbyl_lint(params: ExecuteParams) -> NoReturn:
    """Execute lbyl lint."""
    validate_paths_exist(params.path_objs)
    orchestrator = _setup_lbyl_orchestrator(
        params.path_objs, params.config_file, params.verbose, params.project_root
    )
    lbyl_violations = _run_lbyl_lint(
        orchestrator, params.path_objs, params.recursive, params.parallel
    )

    logger.debug(f"Found {len(lbyl_violations)} LBYL violation(s)")

    format_violations(lbyl_violations, params.format)
    sys.exit(1 if lbyl_violations else 0)


lbyl = create_linter_command(
    "lbyl",
    _execute_lbyl_lint,
    "Check for Look Before You Leap anti-patterns.",
    "Detects LBYL (Look Before You Leap) anti-patterns in Python code that should\n"
    "    be refactored to EAFP (Easier to Ask Forgiveness than Permission) style.\n"
    "    Examples: 'if key in dict: dict[key]' should use try/except KeyError.",
)
