"""
Given a source folder and a destination folder, this script will copy all images
and add to them a white date stamp in the correct orientation at the correct size.

It uses ImageMagick, so make sure you've it installed already!
http://www.imagemagick.org
"""
import logging
from pathlib import Path
import subprocess

import exifread as exif

import logger

# log is preset by the logger module
log = logging.getLogger(logger.LOG_NAME)


SRC_PATH = Path("test-folder/source")
DST_PATH = Path("test-folder/destination")
USED_KEYS = {
    "Image Orientation",
    "EXIF DateTimeOriginal",
    "EXIF ExifImageWidth",
    "EXIF ExifImageLength",
}
DATE_SEP = "."
SIZE_REF = 2160

COVERAGE_FILE = Path("coverage.txt")


def get_metadata(path, keys):
    """Helper function to retrieve specific tags."""
    with open(path, "rb") as file:
        tags = exif.process_file(file, details=False)

    shorten = lambda item: item[0] if len(item) == 1 else item

    return {k: shorten(tags[k].values) for k in keys}


def stamp(file):
    """Datestamps the image pointed to by file."""
    meta = get_metadata(file, USED_KEYS)

    # EXIF Date format: "YYYY:MM:DD HH:MM:SS" with time shown in 24-hour format
    date = meta["EXIF DateTimeOriginal"].split()[0].split(":")[::-1]
    date_stamp = DATE_SEP.join(date)

    min_dimension = min(meta["EXIF ExifImageWidth"], meta["EXIF ExifImageLength"])
    pointsize = (min_dimension * 100) // SIZE_REF
    offset_ratio = (min_dimension * 15) // SIZE_REF

    # ⚠ Warning: magic numbers ahead
    orientation = meta["Image Orientation"]
    if orientation == 6:
        angle = "270x270"
        gravity = "NorthEast"
        y_offset = 2 * offset_ratio
        x_offset = 6 * offset_ratio
    elif orientation == 8:
        angle = "90x90"
        gravity = "SouthWest"
        y_offset = 37 * offset_ratio
        x_offset = 2 * offset_ratio
    elif orientation == 3:
        angle = "180x180"
        gravity = "NorthWest"
        y_offset = 8 * offset_ratio
        x_offset = 37 * offset_ratio
    elif orientation == 1:
        angle = ""
        gravity = "SouthEast"
        y_offset = 0
        x_offset = offset_ratio
    else:
        log.error(f"🔴 Unkown orientation '{orientation}' for file {file}")
        return None

    log.info(f"Processing {file}...")
    log.debug(
        f"Metadata: {orientation=}, "
        f"{meta['EXIF ExifImageWidth']}x{meta['EXIF ExifImageLength']}, "
        f"{meta['EXIF DateTimeOriginal']}"
    )
    # Gestion de l'argument de commande sur Windows : https://stackoverflow.com/a/35900070
    # À explorer, notamment pour l'utilisation de l'argument "shell"
    command = (
        f'convert "{file}" '
        f"-gravity {gravity} "
        f"-fill white "
        f"-pointsize {pointsize} "
        f"-annotate {angle}+{x_offset}+{y_offset} {date_stamp} "
        f'"{DST_PATH}\{file.name}"'
    )
    log.debug(f"Executing command: {command}")
    result = subprocess.run(command, capture_output=True, text=True)
    if result.returncode != 0:
        log.error(f"🔴 Command failed for {file}: {result.stderr}")
        return None
    else:
        return f"{meta['EXIF ExifImageWidth']}x{meta['EXIF ExifImageLength']}_{orientation}{file.suffix.lower()}"


if __name__ == "__main__":
    log.info("📷📆 - Welcome to Photo DateStamper!")
    log.info(f"📝 Log file: {logger.LOG_FILE}")
    DST_PATH.mkdir(parents=True, exist_ok=True)
    COVERAGE_FILE.touch(exist_ok=True)
    with open(COVERAGE_FILE, "r") as file:
        lines = file.readlines()
    coverage = {line.split()[0]: line.split()[1] for line in lines}
    new_coverage = dict()
    try:
        for file in SRC_PATH.iterdir():
            fingerprint = stamp(file)
            if fingerprint is not None and fingerprint not in coverage:
                new_coverage[fingerprint] = str(file)
    finally:
        if new_coverage:
            log.info(
                f"🟡 Execution encountered {len(new_coverage)} new combinations, please report them."
            )
            log.info(f"📝 Updating coverage file: {COVERAGE_FILE}")
            with open(COVERAGE_FILE, "a", encoding="UTF-8") as file:
                for k, v in new_coverage.items():
                    file.write(f"{k} {v}\n")

    log.info("🟢 Processing done.")