"""
Pheser -- Cleaner
Supports:
  - Remove only GPS data
  - Remove all EXIF data entirely
  - Remove specific tags by name
  - Keep only safe tags (no GPS, no device serials)
"""

from __future__ import annotations
import os
from typing import Sequence

from PIL import Image
import piexif

from .utils import output_path


# These tags control how the image is displayed -- never remove them.
_PROTECTED_TAGS = {
    "Orientation", "XResolution", "YResolution",
    "ResolutionUnit", "YCbCrPositioning",
}


def clean(
    input_file: str,
    output_file: str | None = None,
    *,
    mode: str = "gps",
    remove_tags: Sequence[str] | None = None,
    out_dir: str | None = None,
    verbose: bool = True,
) -> str | None:
    """
    Clean metadata from an image.

    Parameters
    ----------
    input_file  : Source image path.
    output_file : Destination path. Auto-generated if None.
    mode        : Cleaning mode:
                    "gps"        -- Remove only GPS IFD (default)
                    "all"        -- Strip all EXIF data
                    "tags"       -- Remove specific tags listed in remove_tags
                    "keep_basic" -- Keep only safe tags (no GPS, no device serials)
    remove_tags : List of tag names to remove (only used when mode="tags").
                  Protected display tags (Orientation etc.) are silently ignored.
    out_dir     : Directory to place the output file.
    verbose     : Print progress messages.

    Returns
    -------
    Output file path on success, None on failure.
    """
    if not os.path.isfile(input_file):
        print(f"[pheser] File not found: {input_file}")
        return None

    prefix = {
        "gps": "clean_gps",
        "all": "clean",
        "tags": "clean_tags",
        "keep_basic": "clean_safe",
    }.get(mode, "clean")

    if output_file is None:
        output_file = output_path(input_file, prefix, out_dir)

    try:
        img = Image.open(input_file)
    except Exception as e:
        print(f"[pheser] Cannot open image: {e}")
        return None

    if "exif" not in img.info:
        img.save(output_file)
        if verbose:
            print(f"[pheser] No EXIF found -- saved plain copy -> {output_file}")
        return output_file

    # mode=all: Pillow saves pixel data without any EXIF block.
    # Orientation is baked into the pixel matrix by Pillow automatically.
    if mode == "all":
        img.save(output_file)
        if verbose:
            print(f"[pheser] All EXIF removed -> {output_file}")
        return output_file

    exif_dict = piexif.load(img.info["exif"])
    removed: list[str] = []

    if mode == "gps":
        if exif_dict.get("GPS"):
            exif_dict["GPS"] = {}
            removed.append("GPS IFD")

    elif mode == "tags":
        if not remove_tags:
            print("[pheser] mode='tags' requires remove_tags list.")
            return None

        # Never allow removing display/geometry tags
        safe_remove = set(remove_tags) - _PROTECTED_TAGS
        skipped = set(remove_tags) & _PROTECTED_TAGS
        if skipped and verbose:
            print(f"[pheser] Skipping protected display tags: {', '.join(skipped)}")

        for ifd in exif_dict:
            # Never touch 1st IFD or thumbnail -- they hold thumbnail orientation
            if ifd in ("thumbnail", "1st"):
                continue
            to_del = []
            for tag in exif_dict[ifd]:
                try:
                    tag_name = piexif.TAGS[ifd][tag]["name"]
                except KeyError:
                    continue
                if tag_name in safe_remove:
                    to_del.append(tag)
                    removed.append(tag_name)
            for tag in to_del:
                del exif_dict[ifd][tag]

    elif mode == "keep_basic":
        exif_dict["GPS"] = {}
        removed.append("GPS IFD")

        _STRIP_TAGS = {
            "Make", "Model", "Software", "HostComputer",
            "CameraOwnerName", "BodySerialNumber", "LensSerialNumber",
            "LensMake", "LensModel", "Artist", "Copyright",
            "ImageDescription", "UserComment",
        } - _PROTECTED_TAGS

        for ifd in ("0th", "Exif"):
            to_del = []
            for tag in exif_dict.get(ifd, {}):
                try:
                    tag_name = piexif.TAGS[ifd][tag]["name"]
                except KeyError:
                    continue
                if tag_name in _STRIP_TAGS:
                    to_del.append(tag)
                    removed.append(tag_name)
            for tag in to_del:
                del exif_dict[ifd][tag]

    exif_bytes = piexif.dump(exif_dict)
    img.save(output_file, exif=exif_bytes)

    if verbose:
        removed_str = ", ".join(removed) if removed else "nothing"
        print(f"[pheser] Removed: {removed_str}")
        print(f"[pheser] Saved -> {output_file}")

    return output_file


def clean_all(input_file: str, output_file: str | None = None, **kwargs) -> str | None:
    """Convenience wrapper: strip ALL EXIF data."""
    return clean(input_file, output_file, mode="all", **kwargs)