"""
SLTK Command Line Interface.

Usage:
    sltk convert <input> <output> --from <format> --to <format>
    sltk evaluate <predictions> <references> --task <task>
    sltk to-elan <input> --output <output.eaf>
    sltk from-elan <input.eaf> --output <output.json>
"""

import json
from pathlib import Path

import click


@click.group()
@click.version_option(package_name="signlangtk")
def main():
    """Sign Language Toolkit - Tools for sign language research."""
    pass


@main.command()
@click.argument("input_path", type=click.Path(exists=True))
@click.argument("output_path", type=click.Path())
@click.option("--from", "from_format", required=True, help="Source pose format")
@click.option("--to", "to_format", required=True, help="Target pose format")
@click.option("--fps", type=float, default=25.0, help="Frames per second")
def convert(input_path, output_path, from_format, to_format, fps):
    """Convert poses between formats."""
    from sltk.data.core import PoseSequence

    try:
        click.echo(f"Loading {input_path} as {from_format}...")
        poses = PoseSequence.load(input_path, format=from_format, fps=fps)
        click.echo(f"  Loaded {poses.num_frames} frames")

        if from_format != to_format:
            click.echo(f"Converting to {to_format}...")
            poses = poses.to_format(to_format)

        click.echo(f"Saving to {output_path}...")
        poses.save(output_path)

        click.echo("Done!")
    except FileNotFoundError:
        raise click.ClickException(f"Input file not found: {input_path}")
    except ValueError as e:
        raise click.ClickException(f"Invalid pose format or data: {e}")
    except PermissionError as e:
        raise click.ClickException(f"Permission denied: {e}")
    except Exception as e:
        raise click.ClickException(f"Conversion failed: {e}")


@main.command()
@click.argument("predictions", type=click.Path(exists=True))
@click.argument("references", type=click.Path(exists=True))
@click.option(
    "--task",
    type=click.Choice(["translation", "segmentation"]),
    required=True,
    help="Evaluation task",
)
@click.option("--output", "-o", type=click.Path(), help="Output JSON file")
@click.option("--tolerance", type=float, default=0.1, help="Boundary tolerance (segmentation)")
@click.option("--encoding", default="utf-8", help="File encoding (default: utf-8)")
def evaluate(predictions, references, task, output, tolerance, encoding):
    """Evaluate predictions against references."""
    # Validate files exist
    pred_path = Path(predictions)
    ref_path = Path(references)

    if not pred_path.exists():
        raise click.ClickException(f"Predictions file not found: {predictions}")
    if not ref_path.exists():
        raise click.ClickException(f"References file not found: {references}")

    try:
        if task == "translation":
            from sltk.metrics.translation import translation_metrics

            try:
                with open(predictions, encoding=encoding) as f:
                    preds = [line.strip() for line in f if line.strip()]
            except UnicodeDecodeError as e:
                raise click.ClickException(
                    f"Failed to read predictions file with encoding '{encoding}': {e}"
                )

            try:
                with open(references, encoding=encoding) as f:
                    refs = [line.strip() for line in f if line.strip()]
            except UnicodeDecodeError as e:
                raise click.ClickException(
                    f"Failed to read references file with encoding '{encoding}': {e}"
                )

            if len(preds) != len(refs):
                raise click.ClickException(
                    f"Length mismatch: {len(preds)} predictions vs {len(refs)} references"
                )

            if not preds:
                raise click.ClickException("Predictions file is empty")
            if not refs:
                raise click.ClickException("References file is empty")

            results = translation_metrics(preds, refs)

        elif task == "segmentation":
            from sltk.io.elan import read_eaf
            from sltk.metrics.segmentation import segmentation_metrics

            try:
                preds = read_eaf(predictions)
            except Exception as e:
                raise click.ClickException(f"Failed to read predictions ELAN file: {e}")

            try:
                refs = read_eaf(references)
            except Exception as e:
                raise click.ClickException(f"Failed to read references ELAN file: {e}")

            results = segmentation_metrics(preds, refs, tolerance_sec=tolerance)

        # Display results
        click.echo("\nResults:")
        for metric, value in sorted(results.items()):
            click.echo(f"  {metric}: {value:.4f}")

        # Save if requested
        if output:
            try:
                with open(output, "w", encoding="utf-8") as f:
                    json.dump(results, f, indent=2)
                click.echo(f"\nSaved to {output}")
            except PermissionError:
                raise click.ClickException(f"Permission denied writing to: {output}")
            except Exception as e:
                raise click.ClickException(f"Failed to save output: {e}")

    except click.ClickException:
        raise
    except Exception as e:
        raise click.ClickException(f"Evaluation failed: {e}")


@main.command("to-elan")
@click.argument("input_path", type=click.Path(exists=True))
@click.option("--output", "-o", type=click.Path(), required=True, help="Output .eaf file")
@click.option("--video", type=click.Path(), help="Source video to link")
@click.option("--tier", default="default", help="ELAN tier name")
def to_elan(input_path, output, video, tier):
    """Export segments to ELAN format.

    Input should be a JSON file with segments:
    [{"start": 0.0, "end": 1.5, "label": "HELLO"}, ...]
    """
    from sltk.data.core import Segment, SegmentList

    # Validate input file exists
    input_path_obj = Path(input_path)
    if not input_path_obj.exists():
        raise click.ClickException(f"Input file not found: {input_path}")

    # Parse JSON
    try:
        with open(input_path, encoding="utf-8") as f:
            data = json.load(f)
    except json.JSONDecodeError as e:
        raise click.ClickException(f"Invalid JSON in input file: {e}")
    except UnicodeDecodeError as e:
        raise click.ClickException(f"Failed to read input file (encoding error): {e}")
    except Exception as e:
        raise click.ClickException(f"Failed to read input file: {e}")

    # Validate JSON schema
    if not isinstance(data, list):
        raise click.ClickException("Invalid JSON schema: expected a list of segment objects")

    if not data:
        raise click.ClickException("Input file contains no segments")

    # Validate each segment has required fields
    for i, segment in enumerate(data):
        if not isinstance(segment, dict):
            raise click.ClickException(
                f"Invalid segment at index {i}: expected an object, got {type(segment).__name__}"
            )
        if "start" not in segment:
            raise click.ClickException(f"Segment at index {i} missing required field 'start'")
        if "end" not in segment:
            raise click.ClickException(f"Segment at index {i} missing required field 'end'")

        # Validate types
        try:
            float(segment["start"])
            float(segment["end"])
        except (TypeError, ValueError):
            raise click.ClickException(
                f"Segment at index {i} has invalid start/end values (must be numeric)"
            )

    try:
        segments = SegmentList(
            [
                Segment(
                    start=s["start"],
                    end=s["end"],
                    label=s.get("label"),
                    tier=s.get("tier", tier),
                    confidence=s.get("confidence"),
                )
                for s in data
            ]
        )

        segments.to_elan(output, video_path=video)
        click.echo(f"Exported {len(segments)} segments to {output}")
    except PermissionError:
        raise click.ClickException(f"Permission denied writing to: {output}")
    except Exception as e:
        raise click.ClickException(f"Failed to export to ELAN: {e}")


@main.command("from-elan")
@click.argument("eaf_path", type=click.Path(exists=True))
@click.option("--output", "-o", type=click.Path(), help="Output JSON file")
@click.option("--tier", multiple=True, help="Tiers to extract (default: all)")
def from_elan(eaf_path, output, tier):
    """Import segments from ELAN format."""
    from sltk.io.elan import read_eaf

    # Validate input file
    eaf_path_obj = Path(eaf_path)
    if not eaf_path_obj.exists():
        raise click.ClickException(f"ELAN file not found: {eaf_path}")

    if eaf_path_obj.suffix.lower() != ".eaf":
        click.echo(f"Warning: File does not have .eaf extension: {eaf_path}")

    # Read ELAN file
    try:
        tiers = list(tier) if tier else None
        segments = read_eaf(eaf_path, tiers=tiers)
    except FileNotFoundError:
        raise click.ClickException(f"ELAN file not found: {eaf_path}")
    except PermissionError:
        raise click.ClickException(f"Permission denied reading: {eaf_path}")
    except Exception as e:
        # Handle corrupt or malformed ELAN files
        error_msg = str(e)
        if "xml" in error_msg.lower() or "parse" in error_msg.lower():
            raise click.ClickException(
                f"Failed to parse ELAN file (possibly corrupt or invalid XML): {e}"
            )
        raise click.ClickException(f"Failed to read ELAN file: {e}")

    click.echo(f"Loaded {len(segments)} segments from {len(segments.tiers)} tiers:")
    for tier_name in segments.tiers:
        tier_segs = segments.filter_by_tier(tier_name)
        click.echo(f"  {tier_name}: {len(tier_segs)} segments")

    if output:
        try:
            data = [
                {
                    "start": s.start,
                    "end": s.end,
                    "duration": s.duration,
                    "label": s.label,
                    "tier": s.tier,
                    "confidence": s.confidence,
                }
                for s in segments
            ]
            with open(output, "w", encoding="utf-8") as f:
                json.dump(data, f, indent=2)
            click.echo(f"\nSaved to {output}")
        except PermissionError:
            raise click.ClickException(f"Permission denied writing to: {output}")
        except Exception as e:
            raise click.ClickException(f"Failed to save output: {e}")


@main.command("info")
@click.argument("path", type=click.Path(exists=True))
def info(path):
    """Show information about a file (H5, ELAN, etc.)."""
    path = Path(path)

    if not path.exists():
        raise click.ClickException(f"File not found: {path}")

    suffix = path.suffix.lower()

    try:
        if suffix == ".h5":
            from sltk.io.h5 import get_h5_metadata

            try:
                meta = get_h5_metadata(path)
            except PermissionError:
                raise click.ClickException(f"Permission denied reading: {path}")
            except Exception as e:
                raise click.ClickException(f"Failed to read H5 file: {e}")

            click.echo(f"H5 File: {path.name}")
            click.echo(f"  Format: {meta.get('format', 'unknown')}")
            click.echo(f"  Frames: {meta.get('num_frames', 'unknown')}")
            click.echo(f"  Features: {', '.join(meta.get('features', [])[:5])}")
            if len(meta.get("features", [])) > 5:
                click.echo(f"    ... and {len(meta['features']) - 5} more")

        elif suffix == ".eaf":
            from sltk.io.elan import get_eaf_metadata, read_eaf

            try:
                meta = get_eaf_metadata(path)
                segments = read_eaf(path)
            except PermissionError:
                raise click.ClickException(f"Permission denied reading: {path}")
            except Exception as e:
                error_msg = str(e)
                if "xml" in error_msg.lower() or "parse" in error_msg.lower():
                    raise click.ClickException(
                        f"Failed to parse ELAN file (possibly corrupt or invalid XML): {e}"
                    )
                raise click.ClickException(f"Failed to read ELAN file: {e}")

            click.echo(f"ELAN File: {path.name}")
            click.echo(f"  Author: {meta.get('author', 'unknown')}")
            click.echo(f"  Tiers: {', '.join(meta.get('tiers', []))}")
            click.echo(f"  Total segments: {len(segments)}")
            for tier_name in meta.get("tiers", []):
                tier_segs = segments.filter_by_tier(tier_name)
                click.echo(f"    {tier_name}: {len(tier_segs)} segments")

        else:
            raise click.ClickException(
                f"Unsupported file type: {suffix}. Supported types: .h5, .eaf"
            )

    except click.ClickException:
        raise
    except Exception as e:
        raise click.ClickException(f"Failed to read file info: {e}")


@main.command()
@click.option("--host", default="0.0.0.0", help="Host to bind to")
@click.option("--port", "-p", default=8000, type=int, help="Port to serve on")
@click.option("--reload", is_flag=True, help="Enable auto-reload for development")
def serve(host, port, reload):
    """Start the SLTK web application (API + frontend)."""
    try:
        import uvicorn
    except ImportError:
        raise click.ClickException(
            "uvicorn is required to run the server. Install with: pip install sltk[api]"
        )

    static_dir = Path(__file__).resolve().parent.parent / "api" / "static"
    if static_dir.is_dir():
        click.echo(f"Serving web UI at http://localhost:{port}")
    else:
        click.echo(f"No frontend build found at {static_dir}")
        click.echo("API-only mode — web UI not available")

    click.echo(f"API docs at http://localhost:{port}/docs")

    uvicorn.run(
        "sltk.api.main:app",
        host=host,
        port=port,
        reload=reload,
        reload_dirs=["sltk"] if reload else None,
        log_level="info",
    )


@main.command("formats")
def formats():
    """List supported pose formats."""
    from sltk.data.formats import list_formats

    fmts = list_formats()
    click.echo("Supported pose formats:\n")

    for name, info in sorted(fmts.items()):
        status = []
        if info.get("can_load"):
            status.append("load")
        if info.get("can_save"):
            status.append("save")

        desc = info.get("description", "")
        click.echo(f"  {name}")
        if desc:
            click.echo(f"    {desc}")
        click.echo(f"    Capabilities: {', '.join(status)}")
        click.echo()


# =============================================================================
# Annotation Conversion Commands
# =============================================================================


@main.command("convert-annotations")
@click.argument("dataset", type=str)
@click.option(
    "--source",
    "-s",
    type=click.Path(exists=True),
    required=True,
    help="Source directory with raw annotations",
)
@click.option(
    "--output",
    "-o",
    type=click.Path(),
    required=True,
    help="Output directory for unified annotations",
)
@click.option(
    "--format",
    "-f",
    "source_format",
    type=str,
    default=None,
    help="Source format (auto-detected if not specified)",
)
@click.option(
    "--generate-manifest/--no-manifest",
    default=True,
    help="Generate manifest.json after conversion",
)
def convert_annotations(dataset, source, output, source_format, generate_manifest):
    """Convert raw annotations to unified format.

    Supported formats: elan, wlasl_json, msasl_json, asldict_json,
    how2sign_csv, asl_citizen_csv, bobsl, csl_daily_json, vtt, phoenix_csv, ytsl_tsv
    """
    from sltk.io.annotations import generate_manifest as gen_manifest
    from sltk.io.converters import convert_dataset

    # Validate source directory exists
    source_path = Path(source)
    if not source_path.exists():
        raise click.ClickException(f"Source directory not found: {source}")
    if not source_path.is_dir():
        raise click.ClickException(f"Source path is not a directory: {source}")

    # Create output directory if needed
    output_path = Path(output)
    try:
        output_path.mkdir(parents=True, exist_ok=True)
    except PermissionError:
        raise click.ClickException(f"Permission denied creating output directory: {output}")
    except Exception as e:
        raise click.ClickException(f"Failed to create output directory: {e}")

    click.echo(f"Converting {dataset} annotations...")
    click.echo(f"  Source: {source}")
    click.echo(f"  Output: {output}")

    if source_format:
        click.echo(f"  Format: {source_format}")
    else:
        click.echo("  Format: auto-detect")

    try:
        # Run conversion
        result = convert_dataset(
            dataset=dataset,
            source_dir=source,
            output_dir=output,
            source_format=source_format,
        )

        click.echo("\nConversion complete:")
        click.echo(f"  Files created: {result.files_created}")
        click.echo(f"  Duration: {result.duration_sec:.2f}s")

        if result.errors:
            click.echo(f"  Errors: {len(result.errors)}")
            for err in result.errors[:5]:
                click.echo(f"    - {err}")
            if len(result.errors) > 5:
                click.echo(f"    ... and {len(result.errors) - 5} more")

        # Generate manifest
        if generate_manifest and result.files_created > 0:
            click.echo("\nGenerating manifest...")
            try:
                manifest = gen_manifest(
                    annotation_dir=output,
                    dataset=dataset,
                    source_format=result.source_format,
                )
                stats = manifest.get("statistics", {})
                click.echo(f"  Total samples: {stats.get('total_samples', 0)}")
                click.echo(f"  Total segments: {stats.get('total_segments', 0)}")
                click.echo(f"  Unique glosses: {stats.get('unique_glosses', 0)}")
            except Exception as e:
                click.echo(f"  Warning: Failed to generate manifest: {e}")

    except ValueError as e:
        raise click.ClickException(f"Invalid configuration: {e}")
    except PermissionError as e:
        raise click.ClickException(f"Permission denied: {e}")
    except Exception as e:
        raise click.ClickException(f"Annotation conversion failed: {e}")


@main.command("validate-annotations")
@click.argument("path", type=click.Path(exists=True))
@click.option(
    "--strict/--no-strict",
    default=False,
    help="Use strict JSON schema validation (requires jsonschema)",
)
def validate_annotations(path, strict):
    """Validate unified annotation files.

    PATH can be a single JSON file or a directory of annotations.
    """
    from sltk.io.annotations import validate_annotation

    path = Path(path)

    # Validate path exists
    if not path.exists():
        raise click.ClickException(f"Path not found: {path}")

    try:
        files_to_check = []

        if path.is_file():
            if path.suffix.lower() != ".json":
                raise click.ClickException(f"Expected a JSON file, got: {path.suffix}")
            files_to_check = [path]
        else:
            if not path.is_dir():
                raise click.ClickException(f"Path is not a file or directory: {path}")
            files_to_check = list(path.glob("*.json"))
            # Exclude manifest
            files_to_check = [f for f in files_to_check if f.name != "manifest.json"]

        if not files_to_check:
            raise click.ClickException(f"No JSON files found in: {path}")

        click.echo(f"Validating {len(files_to_check)} files...")

        valid_count = 0
        invalid_count = 0
        all_errors = []

        for file_path in files_to_check:
            try:
                is_valid, errors = validate_annotation(file_path, strict=strict)

                if is_valid:
                    valid_count += 1
                else:
                    invalid_count += 1
                    all_errors.append((file_path.name, errors))
            except json.JSONDecodeError as e:
                invalid_count += 1
                all_errors.append((file_path.name, [f"Invalid JSON: {e}"]))
            except PermissionError:
                invalid_count += 1
                all_errors.append((file_path.name, ["Permission denied"]))
            except Exception as e:
                invalid_count += 1
                all_errors.append((file_path.name, [f"Error reading file: {e}"]))

        click.echo("\nResults:")
        click.echo(f"  Valid: {valid_count}")
        click.echo(f"  Invalid: {invalid_count}")

        if all_errors:
            click.echo("\nErrors:")
            for filename, errors in all_errors[:10]:
                click.echo(f"  {filename}:")
                for err in errors[:3]:
                    click.echo(f"    - {err}")
                if len(errors) > 3:
                    click.echo(f"    ... and {len(errors) - 3} more")

            if len(all_errors) > 10:
                click.echo(f"\n  ... and {len(all_errors) - 10} more files with errors")

    except click.ClickException:
        raise
    except Exception as e:
        raise click.ClickException(f"Validation failed: {e}")


@main.command("generate-manifest")
@click.argument("annotation_dir", type=click.Path(exists=True))
@click.option("--dataset", "-d", type=str, required=True, help="Dataset name")
@click.option(
    "--format", "-f", "source_format", type=str, default=None, help="Original annotation format"
)
def generate_manifest_cmd(annotation_dir, dataset, source_format):
    """Generate a manifest.json for a unified annotation directory."""
    from sltk.io.annotations import generate_manifest

    # Validate directory exists
    dir_path = Path(annotation_dir)
    if not dir_path.exists():
        raise click.ClickException(f"Directory not found: {annotation_dir}")
    if not dir_path.is_dir():
        raise click.ClickException(f"Path is not a directory: {annotation_dir}")

    # Check for JSON files
    json_files = list(dir_path.glob("*.json"))
    # Exclude existing manifest
    json_files = [f for f in json_files if f.name != "manifest.json"]
    if not json_files:
        raise click.ClickException(f"No annotation JSON files found in: {annotation_dir}")

    click.echo(f"Generating manifest for {dataset}...")
    click.echo(f"  Found {len(json_files)} annotation files")

    try:
        manifest = generate_manifest(
            annotation_dir=annotation_dir,
            dataset=dataset,
            source_format=source_format,
        )

        stats = manifest.get("statistics", {})
        click.echo("\nManifest generated:")
        click.echo(f"  Total samples: {stats.get('total_samples', 0)}")
        click.echo(f"  Total segments: {stats.get('total_segments', 0)}")
        click.echo(f"  Unique glosses: {stats.get('unique_glosses', 0)}")
        click.echo(f"  Unique signers: {stats.get('unique_signers', 0)}")
        click.echo(f"  Total duration: {stats.get('total_duration_sec', 0):.1f}s")

        if stats.get("samples_by_split"):
            click.echo("  Splits:")
            for split, count in stats["samples_by_split"].items():
                click.echo(f"    {split}: {count}")

        click.echo(f"\nSaved to {annotation_dir}/manifest.json")

    except PermissionError:
        raise click.ClickException(f"Permission denied writing manifest to: {annotation_dir}")
    except json.JSONDecodeError as e:
        raise click.ClickException(f"Invalid JSON in annotation files: {e}")
    except Exception as e:
        raise click.ClickException(f"Failed to generate manifest: {e}")


@main.command("annotation-formats")
def annotation_formats():
    """List supported annotation formats for conversion."""
    from sltk.io.converters import list_converters

    converters = list_converters()
    click.echo("Supported annotation formats:\n")

    format_info = {
        "elan": "ELAN .eaf files (BSLCP, BSLCP2)",
        "wlasl_json": "WLASL JSON format (nested gloss/instances)",
        "msasl_json": "MS-ASL JSON format (flat array)",
        "asldict_json": "ASLDict/BSLDict JSON (word entries)",
        "how2sign_csv": "How2Sign CSV (VIDEO_ID, SENTENCE, etc.)",
        "asl_citizen_csv": "ASL Citizen CSV format",
        "phoenix_csv": "Phoenix-2014 CSV (pipe-delimited)",
        "bobsl": "BOBSL TSV + VTT subtitles",
        "csl_daily_json": "CSL-Daily JSON format",
        "vtt": "WebVTT/SRT subtitle files",
        "bslzone": "BSLZone VTT + scene lists",
        "ytsl_tsv": "YTSL-25 TSV format",
        "youtube_asl_json": "YouTube-ASL JSON captions (start/duration/text)",
    }

    for name in sorted(converters):
        desc = format_info.get(name, "")
        click.echo(f"  {name}")
        if desc:
            click.echo(f"    {desc}")
        click.echo()


@main.command("annotation-info")
@click.argument("path", type=click.Path(exists=True))
def annotation_info(path):
    """Show information about a unified annotation file or directory."""
    from sltk.io.annotations import read_manifest, read_unified_annotation

    path = Path(path)

    # Validate path exists
    if not path.exists():
        raise click.ClickException(f"Path not found: {path}")

    try:
        if path.is_file():
            if path.name == "manifest.json":
                # Show manifest info
                try:
                    manifest = read_manifest(path)
                except json.JSONDecodeError as e:
                    raise click.ClickException(f"Invalid JSON in manifest: {e}")
                except PermissionError:
                    raise click.ClickException(f"Permission denied reading: {path}")

                click.echo(f"Manifest: {path.parent.name}")
                click.echo(f"  Dataset: {manifest.get('dataset')}")
                click.echo(f"  Version: {manifest.get('version')}")
                click.echo(f"  Source format: {manifest.get('source_format', 'unknown')}")

                stats = manifest.get("statistics", {})
                click.echo("\nStatistics:")
                click.echo(f"  Total samples: {stats.get('total_samples', 0)}")
                click.echo(f"  Total segments: {stats.get('total_segments', 0)}")
                click.echo(f"  Unique glosses: {stats.get('unique_glosses', 0)}")
                click.echo(f"  Unique signers: {stats.get('unique_signers', 0)}")

                if stats.get("samples_by_split"):
                    click.echo("\n  Samples by split:")
                    for split, count in stats["samples_by_split"].items():
                        click.echo(f"    {split}: {count}")
            else:
                # Show single annotation info
                if path.suffix.lower() != ".json":
                    raise click.ClickException(f"Expected a JSON file, got: {path.suffix}")

                try:
                    sample = read_unified_annotation(path)
                except json.JSONDecodeError as e:
                    raise click.ClickException(f"Invalid JSON in annotation file: {e}")
                except PermissionError:
                    raise click.ClickException(f"Permission denied reading: {path}")
                except KeyError as e:
                    raise click.ClickException(f"Missing required field in annotation: {e}")

                click.echo(f"Sample: {sample.id}")
                click.echo(f"  Dataset: {sample.dataset}")
                click.echo(f"  Split: {sample.split or 'unknown'}")

                if sample.segments:
                    click.echo(f"  Segments: {len(sample.segments)}")
                    for tier in sample.segments.tiers:
                        tier_segs = sample.segments.filter_by_tier(tier)
                        click.echo(f"    {tier}: {len(tier_segs)}")

                if sample.glosses:
                    click.echo(f"  Glosses: {len(sample.glosses)}")
                    if len(sample.glosses) <= 10:
                        click.echo(f"    {' '.join(sample.glosses)}")

                if sample.text:
                    text_preview = (
                        sample.text[:100] + "..." if len(sample.text) > 100 else sample.text
                    )
                    click.echo(f"  Text: {text_preview}")

        else:
            # Directory - show summary
            if not path.is_dir():
                raise click.ClickException(f"Path is not a file or directory: {path}")

            manifest_path = path / "manifest.json"
            if manifest_path.exists():
                try:
                    manifest = read_manifest(manifest_path)
                except json.JSONDecodeError as e:
                    raise click.ClickException(f"Invalid JSON in manifest: {e}")
                except PermissionError:
                    raise click.ClickException(
                        f"Permission denied reading manifest: {manifest_path}"
                    )

                stats = manifest.get("statistics", {})
                click.echo(f"Dataset: {manifest.get('dataset')}")
                click.echo(f"  Samples: {stats.get('total_samples', 0)}")
                click.echo(f"  Segments: {stats.get('total_segments', 0)}")
                click.echo(f"  Glosses: {stats.get('unique_glosses', 0)}")
            else:
                # Count files
                json_files = list(path.glob("*.json"))
                click.echo(f"Directory: {path.name}")
                click.echo(f"  JSON files: {len(json_files)}")
                click.echo("  (No manifest.json found - run 'sltk generate-manifest')")

    except click.ClickException:
        raise
    except Exception as e:
        raise click.ClickException(f"Failed to read annotation info: {e}")


if __name__ == "__main__":
    main()
