"""
Pheser CLI
"""

from __future__ import annotations
import argparse
import sys

from .scanner import scan
from .cleaner import clean
from .remaker import remake
from .redactor import redact
from .exporter import export_report
from .batch import batch_process
from .compare import compare
from . import __version__


def _build_parser() -> argparse.ArgumentParser:
    parser = argparse.ArgumentParser(
        prog="pheser",
        description="Pheser — Photo Metadata Privacy Toolkit",
        formatter_class=argparse.RawTextHelpFormatter,
    )
    parser.add_argument("--version", action="version", version=f"Pheser {__version__}")
    sub = parser.add_subparsers(dest="command", metavar="<command>")

    # ── scan ──────────────────────────────────────────────────────────────────
    p_scan = sub.add_parser("scan", help="Scan and display all metadata")
    p_scan.add_argument("image", help="Image file path")
    p_scan.add_argument("--no-hash",  action="store_true", help="Skip SHA-256 hash")
    p_scan.add_argument("--no-risk",  action="store_true", help="Skip privacy risk score")
    p_scan.add_argument("--no-map",   action="store_true", help="Skip Google Maps link")
    p_scan.add_argument("--export",   metavar="FILE",      help="Also export results to FILE")
    p_scan.add_argument("--fmt",      default="json",
                        choices=["json", "csv", "txt"],    help="Export format (default: json)")

    # ── clean ─────────────────────────────────────────────────────────────────
    p_clean = sub.add_parser("clean", help="Remove metadata from image")
    p_clean.add_argument("image",  help="Image file path")
    p_clean.add_argument("-o", "--output", metavar="FILE",  help="Output file path")
    p_clean.add_argument("--out-dir",  metavar="DIR",       help="Output directory")
    p_clean.add_argument(
        "--mode",
        default="gps",
        choices=["gps", "all", "tags", "keep_basic"],
        help=(
            "gps        – Remove GPS only (default)\n"
            "all        – Strip all EXIF\n"
            "tags       – Remove specific tags (use --tags)\n"
            "keep_basic – Keep only safe tags"
        ),
    )
    p_clean.add_argument("--tags", nargs="+", metavar="TAG",
                         help="Tag names to remove (mode=tags only)")

    # ── remake ────────────────────────────────────────────────────────────────
    p_remake = sub.add_parser("remake", help="Recreate metadata with custom values")
    p_remake.add_argument("image",  help="Image file path")
    p_remake.add_argument("-o", "--output", metavar="FILE")
    p_remake.add_argument("--out-dir", metavar="DIR")
    p_remake.add_argument("--make",        default="Generic")
    p_remake.add_argument("--model",       default="Camera")
    p_remake.add_argument("--software",    default="Pheser")
    p_remake.add_argument("--artist",      default="")
    p_remake.add_argument("--copyright",   default="")
    p_remake.add_argument("--description", default="")
    p_remake.add_argument("--datetime",    metavar="YYYY:MM:DD HH:MM:SS")
    p_remake.add_argument("--inject-gps",  nargs=2, metavar=("LAT", "LON"), type=float,
                          help="Embed GPS coordinates")

    # ── redact ────────────────────────────────────────────────────────────────
    p_redact = sub.add_parser("redact", help="Spoof / randomize metadata")
    p_redact.add_argument("image",  help="Image file path")
    p_redact.add_argument("-o", "--output", metavar="FILE")
    p_redact.add_argument("--out-dir",  metavar="DIR")
    p_redact.add_argument("--spoof-gps",  nargs=2, metavar=("LAT", "LON"), type=float,
                          help="Replace GPS with specific coordinates")
    p_redact.add_argument("--random-gps",  action="store_true",
                          help="Replace GPS with random coordinates")
    p_redact.add_argument("--random-datetime", action="store_true",
                          help="Shift all DateTime fields randomly")
    p_redact.add_argument("--spoof-device", nargs=2, metavar=("MAKE", "MODEL"),
                          help="Replace Make/Model")

    # ── compare ───────────────────────────────────────────────────────────────
    p_compare = sub.add_parser("compare", help="Diff EXIF between two images")
    p_compare.add_argument("image_a", help="First image")
    p_compare.add_argument("image_b", help="Second image")

    # ── batch ─────────────────────────────────────────────────────────────────
    p_batch = sub.add_parser("batch", help="Process a whole directory")
    p_batch.add_argument("directory",  help="Source directory")
    p_batch.add_argument(
        "--op",
        default="clean-gps",
        choices=["clean-gps", "clean-all", "clean-safe", "redact-gps", "redact-random"],
        help="Operation to apply to each image (default: clean-gps)",
    )
    p_batch.add_argument("--out-dir",  metavar="DIR", help="Output directory")
    p_batch.add_argument("--recursive", action="store_true", help="Recurse subdirectories")
    p_batch.add_argument("--dry-run",   action="store_true", help="List files without processing")

    return parser


def main():
    parser = _build_parser()
    args = parser.parse_args()

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

    # ── scan ──────────────────────────────────────────────────────────────────
    if args.command == "scan":
        results = scan(
            args.image,
            show_hash=not args.no_hash,
            show_risk=not args.no_risk,
            show_map=not args.no_map,
            raw=bool(args.export),
        )
        if args.export and results:
            # Re-run in print mode then export
            scan(args.image, show_hash=not args.no_hash,
                 show_risk=not args.no_risk, show_map=not args.no_map)
            export_report(results, args.export, fmt=args.fmt)

    # ── clean ─────────────────────────────────────────────────────────────────
    elif args.command == "clean":
        clean(
            args.image,
            args.output,
            mode=args.mode,
            remove_tags=args.tags,
            out_dir=args.out_dir,
        )

    # ── remake ────────────────────────────────────────────────────────────────
    elif args.command == "remake":
        inject = tuple(args.inject_gps) if args.inject_gps else None
        remake(
            args.image,
            args.output,
            make=args.make,
            model=args.model,
            software=args.software,
            artist=args.artist,
            copyright=args.copyright,
            description=args.description,
            datetime_str=args.datetime,
            inject_gps=inject,
            out_dir=args.out_dir,
        )

    # ── redact ────────────────────────────────────────────────────────────────
    elif args.command == "redact":
        spoof = tuple(args.spoof_gps) if args.spoof_gps else None
        device = tuple(args.spoof_device) if args.spoof_device else None
        redact(
            args.image,
            args.output,
            spoof_gps=spoof,
            randomize_gps=args.random_gps,
            randomize_datetime=args.random_datetime,
            spoof_device=device,
            out_dir=args.out_dir,
        )

    # ── compare ───────────────────────────────────────────────────────────────
    elif args.command == "compare":
        compare(args.image_a, args.image_b)

    # ── batch ─────────────────────────────────────────────────────────────────
    elif args.command == "batch":
        _OP_MAP = {
            "clean-gps":    lambda s, d: clean(s, d, mode="gps",        verbose=False),
            "clean-all":    lambda s, d: clean(s, d, mode="all",        verbose=False),
            "clean-safe":   lambda s, d: clean(s, d, mode="keep_basic", verbose=False),
            "redact-gps":   lambda s, d: redact(s, d, randomize_gps=True,  verbose=False),
            "redact-random":lambda s, d: redact(s, d, randomize_gps=True,
                                                randomize_datetime=True, verbose=False),
        }
        batch_process(
            args.directory,
            _OP_MAP[args.op],
            out_dir=args.out_dir,
            recursive=args.recursive,
            dry_run=args.dry_run,
        )


if __name__ == "__main__":
    main()