#!/usr/bin/env python3
"""
Batch convert ground truth txt label files to JSON format.

Usage:
    python test_scripts/batch_convert_txt_to_json.py <input_dir> <output_dir> [options]

Examples:
    # Convert all txt files in a directory
    python test_scripts/batch_convert_txt_to_json.py /path/to/labels/ /path/to/labels_json/

    # With custom image dimensions
    python test_scripts/batch_convert_txt_to_json.py /path/to/labels/ /path/to/labels_json/ \\
        --image-width 1920 --image-height 1080

    # Recursive conversion (preserving subdirectory structure)
    python test_scripts/batch_convert_txt_to_json.py /path/to/labels/ /path/to/labels_json/ --recursive
"""

import sys
import argparse
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed

# Allow importing from the same test_scripts directory
sys.path.insert(0, str(Path(__file__).parent))
from convert_txt_to_json import convert_txt_to_json


def batch_convert(input_dir, output_dir, img_width=1920, img_height=1080,
                  recursive=False, workers=4, overwrite=False):
    """
    Batch convert all txt label files in input_dir to JSON format.

    Args:
        input_dir:  Path to directory containing .txt label files
        output_dir: Path to directory where .json files will be saved
        img_width:  Image width for coordinate denormalization
        img_height: Image height for coordinate denormalization
        recursive:  If True, search subdirectories recursively
        workers:    Number of parallel worker threads
        overwrite:  If True, overwrite existing JSON files
    """
    input_path = Path(input_dir)
    output_path = Path(output_dir)

    if not input_path.exists():
        raise FileNotFoundError(f"Input directory not found: {input_dir}")

    # Collect all .txt files
    pattern = "**/*.txt" if recursive else "*.txt"
    txt_files = sorted(input_path.glob(pattern))

    if not txt_files:
        print(f"No .txt files found in: {input_dir}")
        return

    print(f"Found {len(txt_files)} txt file(s) in: {input_dir}")
    print(f"Output directory: {output_dir}")
    print(f"Image dimensions: {img_width}x{img_height}")
    print(f"Workers: {workers}, Recursive: {recursive}, Overwrite: {overwrite}")
    print("-" * 60)

    # Build list of (src, dst) pairs
    tasks = []
    skipped = 0
    for txt_file in txt_files:
        # Preserve relative subdirectory structure when recursive
        rel = txt_file.relative_to(input_path)
        json_file = output_path / rel.with_suffix(".json")

        if json_file.exists() and not overwrite:
            skipped += 1
            continue

        json_file.parent.mkdir(parents=True, exist_ok=True)
        tasks.append((txt_file, json_file))

    if skipped:
        print(f"Skipping {skipped} already-converted file(s) (use --overwrite to force).")

    if not tasks:
        print("Nothing to do.")
        return

    # Process files (parallel when workers > 1)
    success = 0
    failed = 0
    errors = []

    def _convert(args):
        src, dst = args
        convert_txt_to_json(str(src), str(dst), img_width, img_height)
        return str(src)

    if workers > 1:
        with ThreadPoolExecutor(max_workers=workers) as executor:
            futures = {executor.submit(_convert, t): t for t in tasks}
            for i, future in enumerate(as_completed(futures), 1):
                src, _ = futures[future]
                try:
                    future.result()
                    success += 1
                    if i % 100 == 0 or i == len(tasks):
                        print(f"  [{i}/{len(tasks)}] done")
                except Exception as e:
                    failed += 1
                    errors.append((str(src), str(e)))
                    print(f"  ERROR: {src} -> {e}")
    else:
        for i, (src, dst) in enumerate(tasks, 1):
            try:
                convert_txt_to_json(str(src), str(dst), img_width, img_height)
                success += 1
                if i % 100 == 0 or i == len(tasks):
                    print(f"  [{i}/{len(tasks)}] {src.name}")
            except Exception as e:
                failed += 1
                errors.append((str(src), str(e)))
                print(f"  ERROR: {src} -> {e}")

    print("-" * 60)
    print(f"Done. Success: {success}, Failed: {failed}, Skipped: {skipped}")
    if errors:
        print("\nFailed files:")
        for path, msg in errors:
            print(f"  {path}: {msg}")


def main():
    parser = argparse.ArgumentParser(
        description="Batch convert ground truth txt label files to JSON format",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=__doc__,
    )
    parser.add_argument("input_dir",  help="Input directory containing .txt label files")
    parser.add_argument("output_dir", help="Output directory for .json files")
    parser.add_argument("--image-width",  type=int, default=1920,
                        help="Image width for coordinate denormalization (default: 1920)")
    parser.add_argument("--image-height", type=int, default=1080,
                        help="Image height for coordinate denormalization (default: 1080)")
    parser.add_argument("--recursive", action="store_true",
                        help="Recursively search subdirectories for txt files")
    parser.add_argument("--workers", type=int, default=4,
                        help="Number of parallel worker threads (default: 4)")
    parser.add_argument("--overwrite", action="store_true",
                        help="Overwrite existing JSON files (default: skip)")

    args = parser.parse_args()

    batch_convert(
        input_dir=args.input_dir,
        output_dir=args.output_dir,
        img_width=args.image_width,
        img_height=args.image_height,
        recursive=args.recursive,
        workers=args.workers,
        overwrite=args.overwrite,
    )


if __name__ == "__main__":
    main()
