#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import re
import sys
import shutil
import tempfile
import subprocess
from datetime import datetime
from pathlib import Path

# === Config ===
SRC_DIR = "/var/www/html/files/script"    # cartella con immagini e musica.mp3
OUT_DIR = "/var/www/html/files/video"     # cartella di destinazione del video
DUR_PER_IMAGE = 25                        # secondi per immagine
FPS = 30                                  # fps finale
WIDTH, HEIGHT = 1920, 1080                # risoluzione finale
AUDIO_FILENAME = "musica.mp3"             # nome file audio dentro SRC_DIR
OUT_NAME_PREFIX = "slideshow"             # prefisso se non specifichi un nome

ALLOWED_EXTS = {".jpg", ".jpeg", ".png", ".webp", ".bmp",
                ".JPG", ".JPEG", ".PNG", ".WEBP", ".BMP"}

# ---------- utility ----------
def natural_key(s: str):
    """Ordina 'img2.jpg' prima di 'img10.jpg'."""
    return [int(t) if t.isdigit() else t.lower() for t in re.split(r'(\d+)', os.path.basename(s))]

def find_images(folder: str):
    files = []
    for name in os.listdir(folder):
        p = os.path.join(folder, name)
        if os.path.isfile(p) and os.path.splitext(name)[1] in ALLOWED_EXTS:
            files.append(p)
    files.sort(key=natural_key)
    return files

def ensure_ffmpeg():
    ffmpeg = shutil.which("ffmpeg")
    if not ffmpeg:
        print("❌ ffmpeg non trovato. Installa con: sudo apt update && sudo apt install -y ffmpeg", file=sys.stderr)
        sys.exit(1)
    return ffmpeg

def run(cmd):
    print("▶", " ".join(shlex_quote(x) for x in cmd))
    subprocess.run(cmd, check=True)

def shlex_quote(s: str) -> str:
    import shlex
    return shlex.quote(str(s))

def sanitize_filename(name: str) -> str:
    # consenti lettere, numeri, _ - e spazio; sostituisci gli altri con _
    name = name.strip()
    name = re.sub(r"[^A-Za-z0-9 _\-]", "_", name)
    name = re.sub(r"\s+", "_", name)  # spazi -> underscore
    if not name:
        name = f"{OUT_NAME_PREFIX}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
    if not name.lower().endswith(".mp4"):
        name += ".mp4"
    return name

def ask_output_path() -> Path:
    # crea la cartella OUT_DIR se non esiste
    out_dir = Path(OUT_DIR)
    out_dir.mkdir(parents=True, exist_ok=True)

    default_name = f"{OUT_NAME_PREFIX}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
    try:
        if sys.stdin.isatty():
            entered = input(f"Nome file video (senza percorso) [default: {default_name}]: ").strip()
        else:
            entered = ""
    except EOFError:
        entered = ""

    fname = sanitize_filename(entered or default_name)
    out_path = out_dir / fname

    # se esiste, chiedi conferma overwrite
    if out_path.exists() and sys.stdin.isatty():
        ans = input(f"Il file '{out_path.name}' esiste già. Sovrascrivere? [s/N]: ").strip().lower()
        if ans not in ("s", "si", "y", "yes"):
            # crea un nome alternativo con timestamp
            fname = f"{Path(fname).stem}_{datetime.now().strftime('%H%M%S')}.mp4"
            out_path = out_dir / fname

    return out_path

# ---------- main ----------
def main():
    src = Path(SRC_DIR)
    if not src.is_dir():
        print(f"❌ Cartella non trovata: {src}", file=sys.stderr); sys.exit(1)

    images = find_images(str(src))
    if not images:
        print(f"❌ Nessuna immagine trovata in {src} (jpg/jpeg/png/webp/bmp).", file=sys.stderr)
        sys.exit(1)

    music = src / AUDIO_FILENAME
    has_audio = music.is_file()

    ffmpeg = ensure_ffmpeg()
    out_final = ask_output_path()

    # Filtro di adattamento (mantiene proporzioni e aggiunge bande)
    vf = (
        f"scale=w={WIDTH}:h={HEIGHT}:force_original_aspect_ratio=decrease,"
        f"pad={WIDTH}:{HEIGHT}:(ow-iw)/2:(oh-ih)/2,"
        f"fps={FPS},format=yuv420p"
    )

    with tempfile.TemporaryDirectory() as tmpdir:
        tmp = Path(tmpdir)

        # 1) Crea clip mp4 uniformi (stesso codec, fps, size) per OGNI immagine
        clip_paths = []
        for idx, img in enumerate(images, 1):
            clip_mp4 = tmp / f"clip_{idx:04d}.mp4"
            cmd = [
                ffmpeg, "-y",
                "-loop", "1", "-t", str(DUR_PER_IMAGE), "-i", img,      # loop immagine
                "-vf", vf,
                "-c:v", "libx264",
                "-pix_fmt", "yuv420p",
                "-preset", "medium",
                "-r", str(FPS),
                str(clip_mp4),
            ]
            run(cmd)
            clip_paths.append(clip_mp4)

        # 2) Concatena i clip con demuxer concat (veloce, -c copy)
        list_file = tmp / "list.txt"
        with list_file.open("w", encoding="utf-8") as f:
            for p in clip_paths:
                f.write(f"file '{p.as_posix()}'\n")

        video_nosound = tmp / "video_nosound.mp4"
        cmd_concat = [
            ffmpeg, "-y",
            "-f", "concat", "-safe", "0", "-i", str(list_file),
            "-c", "copy",
            str(video_nosound),
        ]
        run(cmd_concat)

        # 3) Aggiunge audio (loopato) se presente
        if has_audio:
            cmd_audio = [
                ffmpeg, "-y",
                "-stream_loop", "-1", "-i", str(music),   # loop audio
                "-i", str(video_nosound),
                "-map", "1:v:0", "-map", "0:a:0",
                "-c:v", "copy",
                "-c:a", "aac", "-b:a", "192k",
                "-shortest",
                str(out_final),
            ]
            run(cmd_audio)
        else:
            shutil.copy2(video_nosound, out_final)

    print(f"✅ Slideshow creato: {out_final}")

if __name__ == "__main__":
    main()
