# Source code for stac_check.cli

    import importlib.metadata
    import json
    import sys
    from typing import Optional

    import click
    import requests
    from stac_validator.utilities import is_valid_url

    from stac_check.api_lint import ApiLinter
    from stac_check.display_messages import (
        cli_message,
        collections_message,
        intro_message,
        item_collection_message,
        recursive_message,
    )
    from stac_check.lint import Linter
    from stac_check.utilities import handle_output

    def is_item_collection(file: str, headers: dict = None) -> bool:
        """Detect if a file is an item collection (FeatureCollection with features).

        Args:
            file: Path or URL to the file
            headers: Optional HTTP headers for URL requests

        Returns:
            True if the file is an item collection, False otherwise
        """
        try:
            if is_valid_url(file):
                resp = requests.get(file, headers=headers or {})
                data = resp.json()
            else:
                with open(file) as f:
                    data = json.load(f)

            # Check if it's a FeatureCollection with features
            return (
                isinstance(data, dict)
                and data.get("type") == "FeatureCollection"
                and "features" in data
                and isinstance(data.get("features"), list)
                and len(data.get("features", [])) > 0
            )
        except Exception:
            # If we can't determine, return False
            return False

    @click.option(
        "--collections",
        is_flag=True,
        help="Validate collections endpoint response. Can be combined with --pages. Defaults to one page.",
    )
    @click.option(
        "--item-collection",
        is_flag=True,
        help="Validate item collection response. Can be combined with --pages. Defaults to one page.",
    )
    @click.option(
        "--pages",
        "-p",
        type=int,
        help="Maximum number of pages to validate via --item-collection or --collections. Defaults to one page.",
    )
    @click.option(
        "--recursive",
        "-r",
        is_flag=True,
        help="Recursively validate all related stac objects.",
    )
    @click.option(
        "--max-depth",
        "-m",
        type=int,
        help="Maximum depth to traverse when recursing. Omit this argument to get full recursion. Ignored if `recursive == False`.",
    )
    @click.option(
        "-a", "--assets", is_flag=True, help="Validate assets for format and response."
    )
    @click.option(
        "-l", "--links", is_flag=True, help="Validate links for format and response."
    )
    @click.option(
        "--output",
        "-o",
        type=click.Path(dir_okay=False, writable=True),
        help="Save output to the specified file. Only works with --collections, --item-collection, or --recursive.",
    )
    @click.option(
        "--no-assets-urls",
        is_flag=True,
        help="Disables the opening of href links when validating assets (enabled by default).",
    )
    @click.option(
        "--header",
        type=(str, str),
        multiple=True,
        help="HTTP header to include in the requests. Can be used multiple times.",
    )
    @click.option(
        "--pydantic",
        is_flag=True,
        help="Use pydantic validation (requires stac-pydantic to be installed).",
    )
    @click.option(
        "--verbose",
        "-v",
        is_flag=True,
        help="Enable verbose output.",
    )
    @click.option(
        "--fast",
        is_flag=True,
        help="Use FastJSONSchema for high-speed validation. Skips geometry checks and linting for maximum performance.",
    )
    @click.option(
        "--fast-linting",
        is_flag=True,
        help="Use FastJSONSchema for high-speed validation with linting. Skips geometry checks for maximum performance.",
    )
    @click.command()
    @click.argument("file")
    @click.version_option(version=importlib.metadata.distribution("stac-check").version)
    def main(
        file: str,
        collections: bool,
        item_collection: bool,
        pages: Optional[int],
        recursive: bool,
        max_depth: Optional[int],
        assets: bool,
        links: bool,
        no_assets_urls: bool,
        header: tuple[tuple[str, str], ...],
        pydantic: bool,
        verbose: bool,
        output: Optional[str],
        fast: bool,
        fast_linting: bool,
    ) -> None:
        """Main entry point for the stac-check CLI.

        Args:
            file: The STAC file or URL to validate
            collections: Validate a collections endpoint
            item_collection: Validate an item collection
            pages: Number of pages to validate (for API endpoints)
            recursive: Recursively validate linked STAC objects
            max_depth: Maximum depth for recursive validation
            assets: Validate assets
            links: Validate links
            no_assets_urls: Disable URL validation for assets
            header: Additional HTTP headers
            pydantic: Use stac-pydantic for validation
            verbose: Show verbose output
            output: Save output to file (only with --collections, --item-collection, or --recursive)
            fast: Fast validation mode (skips geometry checks and linting for maximum performance)
            fast_linting: Fast validation mode with linting (skips geometry checks for maximum performance)
        """
        # Resolve fast/fast-linting flags
        if fast_linting:
            fast = True

        # Check if output is used without --collections, --item-collection, or --recursive
        if output and not any([collections, item_collection, recursive]):
            click.echo(
                "Error: --output can only be used with --collections, --item-collection, or --recursive",
                err=True,
            )
            sys.exit(1)
        # Check if pydantic validation is requested but not installed
        if pydantic:
            try:
                importlib.import_module("stac_pydantic")
            except ImportError:
                click.secho(
                    "Warning: stac-pydantic is not installed. Pydantic validation will be disabled.\n"
                    "To enable pydantic validation, install it with: pip install stac-check[pydantic]",
                    fg="yellow",
                )
                pydantic = False

        # Auto-detect item collection if no explicit flag is set
        if not collections and not item_collection and not recursive:
            if is_item_collection(file, headers=dict(header)):
                item_collection = True

        if collections or item_collection:
            # Handle API-based validation (collections or item collections)
            api_linter = ApiLinter(
                source=file,
                object_list_key="collections" if collections else "features",
                pages=pages if pages else 1,
                headers=dict(header),
                verbose=verbose,
                fast=fast,
                fast_linting=fast_linting,
            )
            results = api_linter.lint_all()

            # Create a dummy Linter instance for display purposes
            display_linter = Linter(
                file,
                assets=assets,
                links=links,
                headers=dict(header),
                pydantic=pydantic,
                verbose=verbose,
                fast=fast,
                fast_linting=fast_linting,
            )

            # Show intro message in the terminal
            intro_message(display_linter)

            # Define output generation function (without intro message since we already showed it)
            def generate_output():
                if collections:
                    collections_message(
                        api_linter,
                        results=results,
                        cli_message_func=cli_message,
                        verbose=verbose,
                    )
                elif item_collection:
                    item_collection_message(
                        api_linter,
                        results=results,
                        cli_message_func=cli_message,
                        verbose=verbose,
                    )

            # Handle output (without duplicating the intro message)
            handle_output(output, generate_output)
            sys.exit(0 if all(msg.get("valid_stac") is True for msg in results) else 1)
        else:
            # Handle file-based validation (single file or recursive)
            linter = Linter(
                file,
                assets=assets,
                links=links,
                recursive=recursive,
                max_depth=max_depth,
                assets_open_urls=not no_assets_urls,
                headers=dict(header),
                pydantic=pydantic,
                verbose=verbose,
                fast=fast,
                fast_linting=fast_linting,
            )

            intro_message(linter)

            # Define output generation function (without intro message since we already showed it)
            def generate_output():
                if recursive:
                    recursive_message(linter, cli_message_func=cli_message, verbose=verbose)
                elif fast:
                    # For fast mode, use item_collection_message to show compact summary
                    # even for single items
                    from stac_check.display_messages import _display_fast_validation_summary

                    result = {
                        "path": file,
                        "valid_stac": linter.valid_stac,
                        "asset_type": linter.asset_type,
                        "version": linter.version,
                        "validation_method": "FastJSONSchema",
                        "error_type": linter.error_type,
                        "error_message": linter.error_msg,
                        "best_practices": linter.best_practices_msg,
                        "geometry_errors": [],
                        "schema": linter.schema,
                        "original_object": linter.data,
                    }
                    results = [result]
                    _display_fast_validation_summary(
                        results,
                        total_time=(
                            linter.total_time if hasattr(linter, "total_time") else 0
                        ),
                        schemas=(
                            linter.schemas_checked
                            if hasattr(linter, "schemas_checked")
                            else None
                        ),
                    )
                else:
                    cli_message(linter)

            # Handle output (without duplicating the intro message)
            handle_output(output if recursive else None, generate_output)

            sys.exit(0 if linter.valid_stac else 1)