#!/usr/bin/env python3
"""
Development Tools CLI
Consolidates all development scripts into a single FreyjaCLI implementation.
"""
import os
import sys
import subprocess
import shutil
import glob
import re
import shlex
from pathlib import Path
from typing import Optional, List, Union, Dict, Any, Tuple
from freyja import FreyjaCLI

# Add the project root to the Python path
project_root = Path(__file__).parent.parent
sys.path.insert(0, str(project_root))

# Detect project name from git repository
def get_project_name() -> str:
  """Get project name from git repository or fallback."""
  try:
    result = subprocess.run(
      ['git', 'rev-parse', '--show-toplevel'],
      capture_output=True,
      text=True,
      check=True
    )
    return Path(result.stdout.strip()).name
  except subprocess.CalledProcessError:
    return "project"  # Fallback if not in git repo

PROJECT_NAME = get_project_name()



class FreyjaDevTools:
  """Development toolkit with build, test, and setup commands organized via Freyja's inner class pattern."""

  def __init__(self, verbose: bool = False, dry_run: bool = False) -> None:
    """Initialize with optional verbose output and dry-run mode."""
    self.verbose: bool = verbose
    self.dry_run: bool = dry_run
    self.project_root: Path = project_root
    self.project_name: str = PROJECT_NAME
    self.colors: Dict[str, str] = {
      'red': '\033[0;31m',
      'green': '\033[0;32m',
      'yellow': '\033[1;33m',
      'blue': '\033[0;34m',
      'nc': '\033[0m'  # No Color
    }

  def _run_command(
    self,
    command: Union[str, List[str]],
    description: str = "",
    shell: bool = False,
    capture_output: bool = False,
    check: bool = False,
    timeout: Optional[int] = None
  ) -> Union[bool, subprocess.CompletedProcess]:
    """Execute a command with unified error handling and logging.

    Returns bool for compatibility, or CompletedProcess when capture_output=True."""
    if description:
      print(f"{self.colors['blue']}{description}{self.colors['nc']}")

    # Convert string to list if shell=False for safety
    if isinstance(command, str) and not shell:
      command = shlex.split(command)

    # Display command for verbose/dry-run
    cmd_display = command if isinstance(command, str) else ' '.join(shlex.quote(arg) for arg in command)
    if self.verbose or self.dry_run:
      print(f"Command: {cmd_display}")

    if self.dry_run:
      print("(DRY RUN - command not executed)")
      # Return mock result for dry-run
      return subprocess.CompletedProcess(command, 0, '', '') if capture_output else True

    try:
      result = subprocess.run(
        command,
        shell=shell,
        check=check,
        capture_output=capture_output,
        text=capture_output,  # Use text mode when capturing
        cwd=self.project_root,
        timeout=timeout
      )
      return result if capture_output else (result.returncode == 0)
    except subprocess.CalledProcessError as e:
      if not capture_output:
        self._print(f"Command failed with exit code {e.returncode}", 'error')
      if check:
        raise
      return e if capture_output else False
    except subprocess.TimeoutExpired as e:
      if not capture_output:
        self._print(f"Command timed out after {timeout} seconds", 'error')
      if check:
        raise
      return subprocess.CompletedProcess(command, -1, '', 'Timeout') if capture_output else False
    except FileNotFoundError:
      cmd_name = command[0] if isinstance(command, list) and command else str(command).split()[0]
      if not capture_output:
        self._print(f"Command '{cmd_name}' not found - is it installed and in PATH?", 'error')
      return subprocess.CompletedProcess(command, -1, '', f"Command not found: {cmd_name}") if capture_output else False
    except OSError as e:
      if not capture_output:
        self._print(f"OS error running command: {e}", 'error')
      return subprocess.CompletedProcess(command, -1, '', str(e)) if capture_output else False

  def _print(self, message: str, msg_type: str = 'info') -> None:
    """Print formatted message based on type."""
    icons = {'success': '✅', 'error': '❌', 'info': 'ℹ️', 'warning': '⚠️'}
    colors = {'success': 'green', 'error': 'red', 'info': 'blue', 'warning': 'yellow'}

    color = self.colors.get(colors.get(msg_type, 'blue'), self.colors['blue'])
    icon = icons.get(msg_type, 'ℹ️')
    print(f"{color}{icon} {message}{self.colors['nc']}")

  class Setup:
    """Development environment and self-installation setup operations."""

    def __init__(self, parent) -> None:
      """Initialize with parent FreyjaDevTools instance."""
      self.parent: 'FreyjaDevTools' = parent

    def env(self) -> None:
      """Set up the development environment with dependencies and pre-commit hooks."""
      parent = self.parent
      print(f"{parent.colors['blue']}🚀 Setting up development environment for {parent.project_name}...{parent.colors['nc']}")

      # Install dependencies
      success = parent._run_command("poetry install --with dev", "📦 Installing dependencies with Poetry...")
      if success:
        # Install pre-commit hooks
        success = parent._run_command("poetry run pre-commit install", "🪝 Installing pre-commit hooks...")
        if success:
          # Verify Python version
          parent._run_command("poetry run python --version", "🐍 Python version:")
          parent._print("Development environment setup complete!", 'success')
          print()
          print("Available commands:")
          print("  python bin/dev-tools build compile     # Compile/build package")
          print("  python bin/dev-tools build lint        # Run linters")
          print("  python bin/dev-tools test run          # Run tests")
          print("  python bin/dev-tools build autocommit  # Commit changes with Claude-generated message")
          print("  python bin/dev-tools build tag-version    # Create git tag for HEAD commit")
          print("  python bin/dev-tools build publish     # Publish to PyPI")
        else:
          parent._print("Failed to install pre-commit hooks", 'error')
      else:
        parent._print("Failed to install dependencies", 'error')
      return

    def self(self, force: bool = False) -> None:
      """Compile and install the latest version from dist/, optionally forcing reinstallation."""
      parent = self.parent
      parent._print(f"🔧 Building and installing latest {parent.project_name} version...", 'info')

      # First, build the package
      parent._print("Building package first...", 'info')
      success = parent._run_command("poetry build", "🔨 Building package...")

      if success:
        # Find the latest wheel file
        dist_dir = parent.project_root / "dist"
        if dist_dir.exists():
          wheel_files = list(dist_dir.glob("*.whl"))
          if wheel_files:
            # Get the latest wheel file (by modification time)
            latest_wheel = max(wheel_files, key=lambda p: p.stat().st_mtime)
            parent._print(f"Installing wheel: {latest_wheel.name}", 'info')

            # Install the wheel
            install_cmd = f"pip install {latest_wheel}"
            if force:
              install_cmd += " --force-reinstall"

            success = parent._run_command(install_cmd, f"📦 Installing {latest_wheel.name}...")
            if success:
              # Verify installation
              parent._run_command(
                f"python -c 'import {parent.project_name}; print(f\"{parent.project_name.capitalize()} version: {{{parent.project_name}.__version__ if hasattr({parent.project_name}, \"__version__\") else \"unknown\"}}\"); print(f\"{parent.project_name.capitalize()} location: {{{parent.project_name}.__file__}}\")'",
                "🔍 Verifying installation:"
              )
              parent._print("Self-installation complete!", 'success')
              parent._print(f"You can now use '{parent.project_name}' from anywhere on your system", 'info')
            else:
              parent._print("Installation failed!", 'error')
          else:
            parent._print("No wheel files found in dist/. Build may have failed.", 'error')
        else:
          parent._print("dist/ directory not found. Run build first.", 'error')
      else:
        parent._print("Build failed!", 'error')
      return


  class Build:
    """Build, compilation, and publishing operations."""

    def __init__(self, parent, parallel: bool = True) -> None:
      """Initialize with parent and optional parallel execution."""
      self.parent: 'FreyjaDevTools' = parent
      self.parallel: bool = parallel

    def clean(self) -> None:
      """Clean build artifacts, cache files, and temporary files."""
      parent = self.parent
      parent._print("🧹 Cleaning build artifacts and cache files...", 'info')

      # Patterns to clean
      patterns_to_remove: List[str] = [
        "**/*.pyc",
        "**/__pycache__",
        "**/.ipynb_checkpoints",
        "**/.pytest_cache",
        "build",
        "dist",
        "*.egg-info"
      ]

      removed_count: int = 0
      for pattern in patterns_to_remove:
        for path in glob.glob(pattern, recursive=True):
          path_obj = Path(path)
          try:
            if path_obj.is_dir():
              if not parent.dry_run:
                shutil.rmtree(path_obj)
              if parent.verbose or parent.dry_run:
                print(f"Removed directory: {path}")
              removed_count += 1
            elif path_obj.is_file():
              if not parent.dry_run:
                path_obj.unlink()
              if parent.verbose or parent.dry_run:
                print(f"Removed file: {path}")
              removed_count += 1
          except PermissionError:
            parent._print(f"Permission denied removing {path} - try running with elevated permissions", 'error')
          except OSError as e:
            parent._print(f"OS error removing {path}: {e}", 'error')
          except (IOError, shutil.Error) as e:
            parent._print(f"Failed to remove {path}: {e}", 'error')

      if removed_count > 0:
        parent._print(f"Cleaned {removed_count} items", 'success')
      else:
        parent._print("No items to clean", 'info')
      return

    def lint(self, fix: bool = False) -> None:
      """Run all linting and formatting tools, optionally auto-fixing issues."""
      parent = self.parent
      parent._print("🔍 Running code quality checks...", 'info')

      success: bool = True

      # Run Ruff
      ruff_cmd = "poetry run ruff check ."
      if fix:
        ruff_cmd += " --fix"
      if not parent._run_command(ruff_cmd, "📝 Running Ruff..."):
        success = False

      # Run Black
      black_cmd = "poetry run black ."
      if not fix:
        black_cmd += " --check"
      if not parent._run_command(black_cmd, "⚫ Running Black..."):
        success = False

      # Run MyPy
      if not parent._run_command(f"poetry run mypy {parent.project_name} --ignore-missing-imports", "🔧 Running MyPy..."):
        success = False

      # Run Pylint
      if not parent._run_command(f"poetry run pylint {parent.project_name}", "🐍 Running Pylint..."):
        success = False

      if success:
        parent._print("All code quality checks passed!", 'success')
      else:
        parent._print("Some code quality checks failed!", 'error')
      return

    def compile(self, clean_first: bool = True) -> None:
      """Build the package with Poetry, optionally cleaning artifacts first."""
      parent = self.parent

      if clean_first:
        self.clean()

      parent._print("🔨 Building package with Poetry...", 'info')

      success = parent._run_command("poetry build", "Building package...")
      if success:
        # Show build info
        parent._run_command("ls -la dist/", "📋 Build information:")
        parent._print("Package built successfully!", 'success')
      else:
        parent._print("Build failed!", 'error')
      return

    def publish(self, test_pypi: bool = False) -> None:
      """Build and publish package to PyPI or test PyPI."""
      parent = self.parent
      parent._print(f"📦 Building and publishing {parent.project_name} to PyPI...", 'info')

      # Clean and build first
      self.compile(clean_first=True)

      # Check for PyPI token
      token_var: str = "TEST_PYPI_TOKEN" if test_pypi else "PYPI_TOKEN"
      token_exists: bool = bool(os.environ.get(token_var))

      if token_exists:
        parent._print("🔐 Configuring PyPI authentication...", 'info')

        # Configure repositories
        if test_pypi:
          repo_url = "https://test.pypi.org/legacy/"
          parent._run_command(f"poetry config repositories.testpypi {repo_url}")
          parent._run_command(f"poetry config http-basic.testpypi __token__ {os.environ[token_var]}")
          publish_cmd = "poetry publish -r testpypi"
        else:
          parent._run_command("poetry config repositories.pypi https://upload.pypi.org/legacy/")
          parent._run_command(f"poetry config http-basic.pypi __token__ {os.environ[token_var]}")
          publish_cmd = "poetry publish"

        # Publish
        success = parent._run_command(publish_cmd, "🚀 Publishing to PyPI...")
        if success:
          if test_pypi:
            parent._print(f"Published successfully to https://test.pypi.org/project/{parent.project_name}/", 'success')
            parent._print(f"Install with: pip install --index-url https://test.pypi.org/simple/ {parent.project_name}", 'info')
          else:
            parent._print(f"Published successfully to https://pypi.org/project/{parent.project_name}/", 'success')
            parent._print(f"Install with: pip install {parent.project_name}", 'info')
        else:
          parent._print("Publishing failed!", 'error')
      else:
        parent._print(f"{token_var} environment variable not set", 'error')
        parent._print(f"Please set {token_var} environment variable with your PyPI token", 'error')
      return

    def autocommit(self) -> None:
      """Commit all uncommitted files using Claude to generate an informative commit message."""
      parent = self.parent
      parent._print("💾 Preparing to commit changes...", 'info')

      # Check if there are any changes to commit
      result = parent._run_command(['git', 'status', '--porcelain'], capture_output=True)
      if not isinstance(result, subprocess.CompletedProcess) or not result.stdout.strip():
        parent._print("No changes to commit", 'info')
        return

      # Show what will be committed
      parent._run_command(['git', 'status', '--short'], "Changes to be committed:")

      # Use Claude to generate commit message
      parent._print("🤖 Generating commit message with Claude...", 'info')
      commit_message: Optional[str] = None
      result = parent._run_command(
        ['claude', '-p', 'Ultrathink and commit the uncommitted files, creating an informative message without mentioning claude or phases, or "Co-authored with Claude". There should be no preamble, summary, or afterthoughts.'],
        capture_output=True
      )
      if isinstance(result, subprocess.CompletedProcess) and result.returncode == 0:
        commit_message = result.stdout.strip()
        parent._print(f"Commit message:\n{commit_message}", 'info')
      else:
        parent._print("Failed to generate commit message with Claude", 'error')
        return

      if commit_message:
        # Add all files
        parent._print("📁 Staging all changes...", 'info')
        add_success = parent._run_command(['git', 'add', '-A'], "Adding all files")

        if add_success:
          # Commit with the generated message
          commit_success = parent._run_command(
            ['git', 'commit', '-m', commit_message],
            "Creating commit"
          )

          if commit_success:
            parent._print("🎉 Changes committed successfully!", 'success')
            # Show the commit
            parent._run_command(['git', 'log', '-1', '--oneline'], "Latest commit:")
          else:
            parent._print("Failed to create commit", 'error')
        else:
          parent._print("Failed to stage files", 'error')
      return

    def tag_version(self, version: Optional[str] = None, auto_increment: bool = True) -> None:
      """Create git tag with Claude-generated message, auto-incrementing version if needed."""
      parent = self.parent
      parent._print(f"🏷️  Creating {parent.project_name} version tag...", 'info')

      # Validate we're in a git repository
      result = parent._run_command(['git', 'rev-parse', '--git-dir'], capture_output=True)
      in_git_repo = isinstance(result, subprocess.CompletedProcess) and result.returncode == 0
      if not in_git_repo:
        parent._print("Not in a git repository", 'error')

      if in_git_repo:
        # Determine version to use
        final_version: Optional[str] = version

        if version is None and auto_increment:
          # Get latest tag and auto-increment
          result = parent._run_command(['git', 'describe', '--tags', '--abbrev=0'], capture_output=True)
          if isinstance(result, subprocess.CompletedProcess) and result.returncode == 0:
            latest_tag = result.stdout.strip()
            parent._print(f"Latest tag: {latest_tag}", 'info')

            # Remove 'v' prefix if present and increment patch version
            version_num = latest_tag.lstrip('v')

            # Validate and parse version
            version_match = re.match(r'^(\d+)\.(\d+)\.(\d+)$', version_num)
            if version_match:
              major, minor, patch = map(int, version_match.groups())
              patch += 1
              final_version = f"{major}.{minor}.{patch}"
              parent._print(f"Auto-incrementing to: {final_version}", 'info')
            else:
              parent._print(f"Invalid version format: {version_num} (expected X.Y.Z)", 'error')
              final_version = None
          else:
            parent._print("No existing tags found. Please provide a version manually.", 'error')
            final_version = None

        if final_version is None:
          parent._print("No version provided and auto-increment disabled", 'error')
        else:
          # Remove 'v' prefix if user provided it
          final_version = final_version.lstrip('v')

          # Validate version format
          if re.match(r'^\d+\.\d+\.\d+$', final_version):
            # Check if tag already exists
            tag: str = f"v{final_version}"
            result = parent._run_command(['git', 'rev-parse', tag], capture_output=True)
            tag_exists = isinstance(result, subprocess.CompletedProcess) and result.returncode == 0
            if tag_exists:
              parent._print(f"Tag '{tag}' already exists", 'error')

            if not tag_exists:
              # Update version in pyproject.toml
              parent._print(f"📝 Updating version in pyproject.toml to {final_version}...", 'info')
              pyproject_path = parent.project_root / "pyproject.toml"

              update_success: bool = False
              try:
                with open(pyproject_path, 'r') as f:
                  content = f.read()

                # Update version line
                updated_content = re.sub(
                  r'^version = "[^"]+"',
                  f'version = "{final_version}"',
                  content,
                  count=1,
                  flags=re.MULTILINE
                )

                with open(pyproject_path, 'w') as f:
                  f.write(updated_content)

                parent._print(f"Updated pyproject.toml version to {final_version}", 'success')
                update_success = True
              except FileNotFoundError:
                parent._print(f"pyproject.toml not found at {pyproject_path}", 'error')
              except PermissionError:
                parent._print(f"Permission denied writing to pyproject.toml - check file permissions", 'error')
              except IOError as e:
                parent._print(f"IO error updating pyproject.toml: {e}", 'error')
              except re.error as e:
                parent._print(f"Regex error updating version in pyproject.toml: {e}", 'error')

              if update_success:
                # Commit the version change
                parent._print("💾 Committing version update...", 'info')
                commit_success = parent._run_command(['git', 'add', 'pyproject.toml'], "Staging pyproject.toml")

                if commit_success:
                  commit_msg = f"Bump version to {final_version}"
                  commit_success = parent._run_command(['git', 'commit', '-m', commit_msg], f"Committing version bump")

                  if commit_success:
                    # Use Claude to generate tag message
                    parent._print("🤖 Generating tag message with Claude...", 'info')
                    tag_message: Optional[str] = None
                    result = parent._run_command(
                      ['claude', '-p', 'Create a very short message to be used on a new tag basing it on the most recent commit (HEAD). Return a single string representing the tag description with no preamble, summary, or afterthoughts. Dont mention phases or claude AT ALL'],
                      capture_output=True
                    )
                    if isinstance(result, subprocess.CompletedProcess) and result.returncode == 0:
                      tag_message = result.stdout.strip()
                      parent._print(f"Tag message: {tag_message}", 'info')
                    else:
                      parent._print("Failed to generate tag message with Claude", 'error')

                    if tag_message:
                      # Create the tag on HEAD
                      parent._print(f"Creating tag: {tag}", 'info')

                      # Create the tag
                      result = parent._run_command(
                        ['git', 'tag', '-a', tag, '-m', tag_message, 'HEAD'],
                        capture_output=True
                      )
                      tag_created = isinstance(result, subprocess.CompletedProcess) and result.returncode == 0
                      if tag_created:
                        parent._print(f"Created tag {tag} on HEAD", 'success')
                      else:
                        error_msg = result.stderr if hasattr(result, 'stderr') and result.stderr else "Unknown error"
                        parent._print(f"Failed to create tag: {error_msg}", 'error')

                      if tag_created:
                        # Push commit and tag to remote
                        parent._print("🚀 Pushing commit and tag to remote...", 'info')
                        push_success = parent._run_command(['git', 'push'], "Pushing commit to remote")
                        if push_success:
                          push_success = parent._run_command(['git', 'push', '--tags'], "Pushing tags to remote")
                        if push_success:
                          # Success summary
                          parent._print("🎉 Version updated, tagged, and pushed successfully!", 'success')
                          parent._print(f"Version: {final_version}", 'success')
                          parent._print(f"Tag: {tag}", 'success')
                          parent._print("Pushed to remote repository", 'success')
                        else:
                          parent._print("Failed to push to remote. Commit and tag created locally.", 'error')
                          parent._print(f"To push manually, run: {parent.colors['blue']}git push && git push --tags{parent.colors['nc']}", 'info')
                  else:
                    parent._print("Failed to commit version change", 'error')
                else:
                  parent._print("Failed to stage pyproject.toml", 'error')
          else:
            parent._print(f"Invalid version format: {final_version} (expected X.Y.Z)", 'error')
      return


  class Test:
    """Testing, diagnostics, and quality assurance operations."""

    def __init__(self, parent, coverage: bool = True) -> None:
      """Initialize with parent and optional coverage reporting."""
      self.parent: 'FreyjaDevTools' = parent
      self.coverage: bool = coverage

    def run(self, pattern: str = "", parallel: bool = False, verbose_output: bool = False) -> None:
      """Run test suite with optional filtering, parallelization, and coverage."""
      parent = self.parent
      parent._print("🧪 Running tests with coverage...", 'info')

      # Build test command
      cmd_parts: List[str] = ["poetry run pytest"]

      if self.coverage:
        cmd_parts.extend([f"--cov={parent.project_name}", "--cov-report=term-missing", "--cov-report=html"])

      if verbose_output:
        cmd_parts.append("-v")

      if parallel:
        cmd_parts.append("-n auto")

      if pattern:
        cmd_parts.append(f"-k {pattern}")

      test_command = " ".join(cmd_parts)

      success = parent._run_command(test_command)
      if success:
        parent._print("📊 Coverage report generated in htmlcov/", 'info')
        parent._print("Tests completed successfully!", 'success')
      else:
        parent._print("Tests failed!", 'error')
      return

    def completion(self, examples_only: bool = False) -> None:
      """Test shell completion functionality, optionally just examples."""
      parent = self.parent
      parent._print("🔧 Testing shell completion functionality...", 'info')

      # Set up environment
      os.environ['PYTHONPATH'] = str(parent.project_root)
      os.chdir(parent.project_root)

      tests_passed: int = 0
      tests_failed: int = 0
      critical_failures: int = 0

      def run_completion_test(test_name: str, test_command: str, expected_pattern: str, critical: bool = False) -> bool:
        nonlocal tests_passed, tests_failed, critical_failures

        test_result: bool = False

        if parent.verbose:
          print(f"Running test: {test_name}")
          print(f"Command: {test_command}")

        result = parent._run_command(shlex.split(test_command), capture_output=True, timeout=10)

        if isinstance(result, subprocess.CompletedProcess):
          if result.returncode == 0 and (expected_pattern in result.stdout or expected_pattern in result.stderr):
            if parent.verbose:
              parent._print(f"✅ {test_name}", 'success')
            tests_passed += 1
            test_result = True
          else:
            parent._print(f"❌ {test_name}", 'error')
            if parent.verbose:
              print(f"Expected pattern: {expected_pattern}")
              if hasattr(result, 'stdout'):
                print(f"Stdout: {result.stdout[:200]}")
              if hasattr(result, 'stderr'):
                print(f"Stderr: {result.stderr[:200]}")
            tests_failed += 1
            if critical:
              critical_failures += 1
        else:
          # Timeout or other error
          parent._print(f"⏰ {test_name} - TIMEOUT or ERROR", 'error')
          tests_failed += 1
          if critical:
            critical_failures += 1

        return test_result

      # Test basic completion functionality
      if not examples_only:
        parent._print("Testing basic completion system...", 'info')

        # Test help completion
        run_completion_test(
          "Help completion",
          "python examples/cls_example --help",
          "usage:",
          critical=True
        )

        # Test command completion
        run_completion_test(
          "Command completion",
          "python examples/cls_example completion install",
          "completion",
          critical=False
        )

      # Test examples completion
      parent._print("Testing examples completion...", 'info')

      # Test cls_example basic functionality
      run_completion_test(
        "cls_example help",
        "python examples/cls_example --help",
        "usage:",
        critical=True
      )

      # Test cls_example command execution
      run_completion_test(
        "cls_example command execution",
        "python examples/cls_example file-operations--process-single --input-file test.txt --dry-run",
        "test.txt",
        critical=False
      )

      # Test multi-class example
      run_completion_test(
        "multi_class_example help",
        "python examples/multi_class_example --help",
        "usage:",
        critical=False
      )

      # Print results
      total_tests: int = tests_passed + tests_failed
      parent._print(f"Completion test results: {tests_passed}/{total_tests} passed", 'info')

      if critical_failures > 0:
        parent._print(f"❌ {critical_failures} critical failures detected!", 'error')
      elif tests_failed > 0:
        parent._print(f"⚠️  {tests_failed} non-critical tests failed", 'warning')
      else:
        parent._print("All completion tests passed!", 'success')
      return

    def diagnose(self, include_env: bool = True, include_completion: bool = True) -> None:
      """Run comprehensive diagnostic analysis for development issues."""
      parent = self.parent
      parent._print("🔍 Running comprehensive diagnostic analysis...", 'info')

      if include_env:
        parent._print("=== Environment Variable Analysis ===", 'info')
        print(f"Current shell: {os.environ.get('SHELL', 'Unknown')}")
        print(f"Current PID: {os.getpid()}")
        print()

        # Check project-related environment variables
        project_vars: Dict[str, str] = {k: v for k, v in os.environ.items() if parent.project_name.lower() in k.lower() or 'comp_' in k.lower()}
        if project_vars:
          print(f"{parent.project_name.capitalize()} completion environment variables:")
          for k, v in project_vars.items():
            print(f"  {k}={v}")
        else:
          print(f"No {parent.project_name.capitalize()} completion environment variables found")
        print()

      if include_completion:
        parent._print("=== Completion System Analysis ===", 'info')

        # Test completion system availability
        result = parent._run_command(
          ['python', 'examples/cls_example', 'completion', '--help'],
          capture_output=True,
          timeout=5
        )
        if isinstance(result, subprocess.CompletedProcess) and result.returncode == 0:
          parent._print("Completion system is available", 'success')
        else:
          parent._print("Completion system unavailable or broken", 'error')

        # Test shell-specific completion
        shell: str = os.environ.get('SHELL', '')
        if 'bash' in shell:
          parent._run_command(f"complete -p | grep -i {parent.project_name} || echo 'No bash completion found'", "Bash completion status:")
        elif 'zsh' in shell:
          parent._run_command(f"compdef | grep -i {parent.project_name} || echo 'No zsh completion found'", "Zsh completion status:")

        print()

      # Python environment check
      parent._print("=== Python Environment ===", 'info')
      parent._run_command("poetry run python --version", "Python version:")
      parent._run_command(f"poetry run python -c 'import {parent.project_name}; print(f\"{parent.project_name.capitalize()} module: {{{parent.project_name}.__file__}}\")'", f"{parent.project_name.capitalize()} module location:")

      # Project structure check
      parent._print("=== Project Structure ===", 'info')
      important_files: List[str] = [
        "pyproject.toml",
        f"{parent.project_name}/__init__.py",
        "examples/cls_example",
        "examples/multi_class_example"
      ]

      for file_path in important_files:
        full_path: Path = parent.project_root / file_path
        if full_path.exists():
          parent._print(f"✅ {file_path} exists", 'success')
        else:
          parent._print(f"❌ {file_path} missing", 'error')

      parent._print("Diagnostic analysis complete!", 'success')
      return



if __name__ == '__main__':
  # Create the CLI instance and store reference for inner classes
  dev_tools = FreyjaDevTools()
  sys.modules[__name__].__dict__['_parent_instance'] = dev_tools

  cli = FreyjaCLI(FreyjaDevTools, title=f"{dev_tools.project_name.capitalize()} Development Tools")
  result = cli.run()
  sys.exit(result if isinstance(result, int) else 0)
