"""
Pheser — Batch Processor
Apply scan / clean / redact / remake to entire directories.
"""

from __future__ import annotations
import os
from typing import Callable, Any

from .utils import is_supported, SUPPORTED_EXTENSIONS


def batch_process(
    directory: str,
    operation: Callable[[str, str], Any],
    *,
    out_dir: str | None = None,
    recursive: bool = False,
    dry_run: bool = False,
    verbose: bool = True,
) -> dict[str, Any]:
    """
    Apply an operation to all supported images in a directory.

    Parameters
    ----------
    directory : Source directory.
    operation : Callable(input_path, output_path) — e.g. a lambda wrapping clean().
    out_dir   : Where to save output files. Defaults to a `pheser_out/` subfolder.
    recursive : Recurse into subdirectories.
    dry_run   : List files without processing them.
    verbose   : Print per-file results.

    Returns
    -------
    {
        "processed": [...],
        "skipped":   [...],
        "errors":    [...],
    }

    Example
    -------
    from pheser import clean, batch_process

    batch_process(
        "photos/",
        lambda src, dst: clean(src, dst, mode="gps", verbose=False),
        out_dir="photos_clean/",
        recursive=True,
    )
    """
    if not os.path.isdir(directory):
        print(f"[pheser]  Not a directory: {directory}")
        return {"processed": [], "skipped": [], "errors": []}

    if out_dir is None:
        out_dir = os.path.join(directory, "pheser_out")

    os.makedirs(out_dir, exist_ok=True)

    results: dict[str, list] = {"processed": [], "skipped": [], "errors": []}

    # Collect files
    files: list[str] = []
    if recursive:
        for root, _, fnames in os.walk(directory):
            for f in fnames:
                files.append(os.path.join(root, f))
    else:
        files = [os.path.join(directory, f) for f in os.listdir(directory)]

    image_files = [f for f in files if os.path.isfile(f) and is_supported(f)]

    if not image_files:
        print(f"[pheser] ℹ  No supported images found in: {directory}")
        print(f"[pheser]    Supported extensions: {', '.join(sorted(SUPPORTED_EXTENSIONS))}")
        return results

    total = len(image_files)
    if verbose:
        print(f"[pheser]  Found {total} image(s) in '{directory}'")
        if dry_run:
            print("[pheser]  DRY RUN — no files will be modified\n")

    for i, src in enumerate(image_files, 1):
        rel = os.path.relpath(src, directory)
        # Mirror subdirectory structure inside out_dir
        dst_dir = os.path.join(out_dir, os.path.dirname(rel))
        os.makedirs(dst_dir, exist_ok=True)
        dst = os.path.join(dst_dir, os.path.basename(src))

        if verbose:
            print(f"  [{i}/{total}] {rel}", end=" ... ")

        if dry_run:
            results["processed"].append(src)
            if verbose:
                print("(skipped — dry run)")
            continue

        try:
            result = operation(src, dst)
            if result:
                results["processed"].append(src)
                if verbose:
                    print("")
            else:
                results["errors"].append(src)
                if verbose:
                    print(" operation returned None")
        except Exception as e:
            results["errors"].append(src)
            if verbose:
                print(f" {e}")

    if verbose:
        print(f"\n[pheser] Done — {len(results['processed'])} processed, "
              f"{len(results['errors'])} errors")
        if not dry_run:
            print(f"[pheser] Output → {out_dir}")

    return results