#!/usr/bin/env python3
"""Main CLI entry point for MAID Runner.

Provides a unified command-line interface with subcommands:
- maid --version
- maid init ...
- maid validate ...
- maid snapshot ...
- maid snapshot-system ...
- maid test ...
- maid manifests ...
- maid schema
"""

import argparse
import sys

from maid_runner import __version__


def main():
    """Main CLI entry point with subcommands."""
    parser = argparse.ArgumentParser(
        prog="maid",
        description="MAID Runner - Manifest-driven AI Development validation tool",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    parser.add_argument(
        "--version",
        action="version",
        version=f"maid-runner {__version__}",
        help="Show version and exit",
    )

    subparsers = parser.add_subparsers(dest="command", help="Available commands")

    # Validate subcommand
    validate_parser = subparsers.add_parser(
        "validate",
        help="Validate manifest against implementation or behavioral test files",
        description="Validate manifest against implementation or behavioral test files",
    )
    validate_parser.add_argument(
        "manifest_path",
        nargs="?",
        help="Path to the manifest JSON file (mutually exclusive with --manifest-dir)",
    )
    validate_parser.add_argument(
        "--validation-mode",
        choices=["implementation", "behavioral"],
        default="implementation",
        help="Validation mode: 'implementation' (default) checks definitions, 'behavioral' checks usage",
    )
    validate_parser.add_argument(
        "--use-manifest-chain",
        action="store_true",
        help="Use manifest chain to merge all related manifests (enables file tracking analysis; automatically enabled for directory validation)",
    )
    validate_parser.add_argument(
        "--quiet",
        "-q",
        action="store_true",
        help="Only output errors (suppress success messages)",
    )
    validate_parser.add_argument(
        "--manifest-dir",
        help="Directory containing manifests to validate (mutually exclusive with manifest_path)",
    )

    # Snapshot subcommand
    snapshot_parser = subparsers.add_parser(
        "snapshot",
        help="Generate MAID snapshot manifests from existing Python files",
        description="Generate MAID snapshot manifests from existing Python files",
    )
    snapshot_parser.add_argument(
        "file_path", help="Path to the Python file to snapshot"
    )
    snapshot_parser.add_argument(
        "--output-dir",
        default="manifests",
        help="Directory to write the manifest (default: manifests)",
    )
    snapshot_parser.add_argument(
        "--force",
        action="store_true",
        help="Overwrite existing manifests without prompting",
    )
    snapshot_parser.add_argument(
        "--skip-test-stub",
        action="store_true",
        help="Skip test stub generation (stubs are generated by default)",
    )

    # Snapshot-system subcommand
    snapshot_system_parser = subparsers.add_parser(
        "snapshot-system",
        help="Generate system-wide manifest snapshot from all active manifests",
        description="Generate system-wide manifest snapshot aggregating artifacts and validation commands from all active manifests",
    )
    snapshot_system_parser.add_argument(
        "--output",
        default="system.manifest.json",
        help="Output file path for the system manifest (default: system.manifest.json)",
    )
    snapshot_system_parser.add_argument(
        "--manifest-dir",
        default="manifests",
        help="Directory containing manifests (default: manifests)",
    )
    snapshot_system_parser.add_argument(
        "--quiet",
        "-q",
        action="store_true",
        help="Suppress informational output (errors still shown)",
    )

    # Test subcommand
    test_parser = subparsers.add_parser(
        "test",
        help="Run validation commands from all non-superseded manifests",
        description="Run validation commands from all non-superseded manifests",
    )
    test_parser.add_argument(
        "--manifest",
        "-m",
        help="Run validation commands for a single manifest (filename relative to manifest-dir or absolute path)",
    )
    test_parser.add_argument(
        "--manifest-dir",
        default="manifests",
        help="Directory containing manifests (default: manifests)",
    )
    test_parser.add_argument(
        "--fail-fast",
        action="store_true",
        help="Stop execution on first failure",
    )
    test_parser.add_argument(
        "--verbose",
        "-v",
        action="store_true",
        help="Show detailed command output",
    )
    test_parser.add_argument(
        "--quiet",
        "-q",
        action="store_true",
        help="Only show summary (suppress per-manifest output)",
    )
    test_parser.add_argument(
        "--timeout",
        type=int,
        default=300,
        help="Command timeout in seconds (default: 300)",
    )

    # List-manifests subcommand
    list_manifests_parser = subparsers.add_parser(
        "manifests",
        help="List all manifests that reference a given file",
        description="List all manifests that reference a given file, categorized by how they reference it (created, edited, or read)",
    )
    list_manifests_parser.add_argument(
        "file_path", help="Path to the file to search for in manifests"
    )
    list_manifests_parser.add_argument(
        "--manifest-dir",
        default="manifests",
        help="Directory containing manifests (default: manifests)",
    )
    list_manifests_parser.add_argument(
        "--quiet",
        "-q",
        action="store_true",
        help="Show minimal output (just manifest names)",
    )

    # Init subcommand
    init_parser = subparsers.add_parser(
        "init",
        help="Initialize MAID methodology in an existing repository",
        description="Initialize MAID methodology by creating directory structure and documentation",
    )
    init_parser.add_argument(
        "--target-dir",
        default=".",
        help="Target directory to initialize (default: current directory)",
    )
    init_parser.add_argument(
        "--force",
        action="store_true",
        help="Overwrite existing files without prompting",
    )

    # Generate-stubs subcommand
    generate_stubs_parser = subparsers.add_parser(
        "generate-stubs",
        help="Generate test stubs from existing manifest",
        description="Generate failing test stubs from an existing manifest file",
    )
    generate_stubs_parser.add_argument(
        "manifest_path", help="Path to the manifest file"
    )

    # Schema subcommand
    subparsers.add_parser(
        "schema",
        help="Output the manifest JSON schema",
        description="Output the manifest JSON schema for agent consumption",
    )

    args = parser.parse_args()

    if not args.command:
        parser.print_help()
        sys.exit(1)

    if args.command == "validate":
        from maid_runner.cli.validate import run_validation

        # Check for mutual exclusivity
        if args.manifest_path and args.manifest_dir:
            parser.error(
                "Cannot specify both manifest_path and --manifest-dir. Use one or the other."
            )

        # Default to manifests directory if neither is provided
        manifest_dir = args.manifest_dir
        if not args.manifest_path and not args.manifest_dir:
            manifest_dir = "manifests"

        # When validating a directory, always use manifest chain
        # This is the expected behavior for directory validation
        # For single-file validation, respect the user's flag
        use_manifest_chain = args.use_manifest_chain
        if manifest_dir:
            # Directory validation: use chain by default
            # User can still force it off by explicitly passing the flag for single files
            use_manifest_chain = True

        run_validation(
            args.manifest_path,
            args.validation_mode,
            use_manifest_chain,
            args.quiet,
            manifest_dir,
        )
    elif args.command == "snapshot":
        from maid_runner.cli.snapshot import run_snapshot

        run_snapshot(args.file_path, args.output_dir, args.force, args.skip_test_stub)
    elif args.command == "snapshot-system":
        from maid_runner.cli.snapshot_system import run_snapshot_system

        run_snapshot_system(args.output, args.manifest_dir, args.quiet)
    elif args.command == "test":
        from maid_runner.cli.test import run_test

        run_test(
            args.manifest_dir,
            args.fail_fast,
            args.verbose,
            args.quiet,
            args.timeout,
            args.manifest,
        )
    elif args.command == "manifests":
        from maid_runner.cli.list_manifests import run_list_manifests

        run_list_manifests(args.file_path, args.manifest_dir, args.quiet)
    elif args.command == "init":
        from maid_runner.cli.init import run_init

        run_init(args.target_dir, args.force)
    elif args.command == "generate-stubs":
        from maid_runner.cli.snapshot import generate_test_stub
        import json
        from pathlib import Path

        # Load the manifest
        manifest_path = Path(args.manifest_path)
        if not manifest_path.exists():
            print(f"Error: Manifest not found: {args.manifest_path}", file=sys.stderr)
            sys.exit(1)

        try:
            with open(manifest_path, "r") as f:
                manifest_data = json.load(f)

            # Generate the stub
            stub_path = generate_test_stub(manifest_data, str(manifest_path))
            print(f"Test stub generated: {stub_path}")

        except json.JSONDecodeError as e:
            print(f"Error: Invalid JSON in manifest: {e}", file=sys.stderr)
            sys.exit(1)
        except KeyError as e:
            print(f"Error: Missing required field in manifest: {e}", file=sys.stderr)
            sys.exit(1)
        except FileNotFoundError as e:
            print(f"Error: File not found: {e}", file=sys.stderr)
            sys.exit(1)
        except PermissionError as e:
            print(f"Error: Permission denied: {e}", file=sys.stderr)
            sys.exit(1)
        except Exception as e:
            print(f"Error generating stub: {e}", file=sys.stderr)
            sys.exit(1)
    elif args.command == "schema":
        from maid_runner.cli.schema import run_schema

        run_schema()
    else:
        parser.print_help()
        sys.exit(1)


if __name__ == "__main__":
    main()
