"""
Pheser — Redactor
Spoof or randomize sensitive EXIF fields without fully stripping them.
Useful for sharing images with plausible-but-fake metadata.
"""

from __future__ import annotations
import os
import random
from datetime import datetime, timedelta

from PIL import Image
import piexif

from .utils import output_path, deg_to_rational


def redact(
    input_file: str,
    output_file: str | None = None,
    *,
    spoof_gps: tuple[float, float] | None = None,
    randomize_gps: bool = False,
    randomize_datetime: bool = False,
    spoof_device: tuple[str, str] | None = None,
    out_dir: str | None = None,
    verbose: bool = True,
) -> str | None:
    """
    Spoof / randomize EXIF fields rather than deleting them.

    Parameters
    ----------
    input_file      : Source image path.
    output_file     : Destination path.
    spoof_gps       : Replace GPS with exact (lat, lon) you supply.
    randomize_gps   : Replace GPS with random coordinates worldwide.
    randomize_datetime : Shift all DateTime fields by a random offset (±1–5 years).
    spoof_device    : Replace Make/Model with (make, model) tuple.
    out_dir         : Output directory.
    verbose         : Print progress.

    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

    if output_file is None:
        output_file = output_path(input_file, "redact", 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 — saved plain copy → {output_file}")
        return output_file

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

    # ── GPS spoofing ───────────────────────────────────────────────────────────
    target_gps: tuple[float, float] | None = None

    if spoof_gps:
        target_gps = spoof_gps
    elif randomize_gps:
        target_gps = (
            round(random.uniform(-85.0, 85.0), 6),
            round(random.uniform(-180.0, 180.0), 6),
        )

    if target_gps:
        lat, lon = target_gps
        lat_ref = b"N" if lat >= 0 else b"S"
        lon_ref = b"E" if lon >= 0 else b"W"
        exif_dict["GPS"][piexif.GPSIFD.GPSLatitudeRef] = lat_ref
        exif_dict["GPS"][piexif.GPSIFD.GPSLatitude] = deg_to_rational(lat)
        exif_dict["GPS"][piexif.GPSIFD.GPSLongitudeRef] = lon_ref
        exif_dict["GPS"][piexif.GPSIFD.GPSLongitude] = deg_to_rational(lon)
        changes.append(f"GPS → ({lat}, {lon})")

    # ── DateTime randomization ─────────────────────────────────────────────────
    if randomize_datetime:
        days_offset = random.randint(365, 365 * 5) * random.choice([-1, 1])
        dt_fmt = "%Y:%m:%d %H:%M:%S"

        _DT_TAGS = [
            ("0th",  piexif.ImageIFD.DateTime),
            ("Exif", piexif.ExifIFD.DateTimeOriginal),
            ("Exif", piexif.ExifIFD.DateTimeDigitized),
        ]

        for ifd, tag in _DT_TAGS:
            if tag in exif_dict.get(ifd, {}):
                raw = exif_dict[ifd][tag]
                try:
                    dt_str = raw.decode() if isinstance(raw, bytes) else raw
                    dt_obj = datetime.strptime(dt_str.strip("\x00"), dt_fmt)
                    new_dt = dt_obj + timedelta(days=days_offset)
                    exif_dict[ifd][tag] = new_dt.strftime(dt_fmt).encode()
                except Exception:
                    pass

        changes.append(f"DateTime shifted by {days_offset:+d} days")

    # ── Device spoofing ────────────────────────────────────────────────────────
    if spoof_device:
        make, model = spoof_device
        exif_dict["0th"][piexif.ImageIFD.Make] = make.encode()
        exif_dict["0th"][piexif.ImageIFD.Model] = model.encode()
        # Remove serial numbers
        for tag in (piexif.ExifIFD.BodySerialNumber, piexif.ExifIFD.LensSerialNumber):
            exif_dict["Exif"].pop(tag, None)
        changes.append(f"Device → {make} / {model}")

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

    if verbose:
        if changes:
            print(f"[pheser]  Redacted: {'; '.join(changes)}")
        else:
            print("[pheser]   No redaction options specified — file copied as-is.")
        print(f"[pheser]    Saved → {output_file}")

    return output_file