"""
youtube_auto_upload.py
----------------------
Scanne un dossier pour les fichiers .mp4, les uploade sur YouTube via l'API Google,
puis les déplace dans un sous-dossier "done/".

Anti-ban :
  - Délai configurable entre chaque upload (défaut : 60s)
  - Retry exponentiel en cas d'erreur quota (429 / 503)
  - Fichier de log pour tracer les uploads déjà faits (évite les doublons)
  - Un seul upload à la fois, jamais en parallèle

Prérequis :
  pip install google-api-python-client google-auth-httplib2 google-auth-oauthlib

Authentification :
  1. Crée un projet sur https://console.cloud.google.com
  2. Active l'API "YouTube Data API v3"
  3. Crée des identifiants OAuth 2.0 (type "Application de bureau")
  4. Télécharge le fichier JSON → renomme-le "client_secrets.json"
  5. Place-le dans le même dossier que ce script
"""

import os
import time
import json
import logging
import shutil
import datetime

from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from googleapiclient.errors import HttpError
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials

# ─────────────────────────────────────────────
# CONFIGURATION — adapte ces valeurs
# ─────────────────────────────────────────────

WATCH_FOLDER = "/home/videos/processed/ghostofatale"
DONE_FOLDER  = "/home/videos/processed/ghostofatale/done"
CLIENT_SECRETS    = "client_secrets.json"
TOKEN_FILE        = "token.json"
UPLOADED_LOG      = "uploaded.json"  # Fichier de suivi des uploads déjà faits

DELAY_BETWEEN     = 60               # Secondes entre chaque upload (anti-spam)
SCAN_INTERVAL     = 300              # Secondes entre chaque scan du dossier
MAX_RETRIES       = 5                # Nombre max de tentatives en cas d'erreur quota
RETRY_BASE_DELAY  = 30              # Délai de base avant retry (doublé à chaque tentative)

PRIVACY_STATUS    = "private"        # "private", "unlisted" ou "public"
CATEGORY_ID       = "20"             # 20 = Gaming

SCOPES = ["https://www.googleapis.com/auth/youtube.upload"]

# ─────────────────────────────────────────────

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.FileHandler("uploader.log"),
        logging.StreamHandler()
    ]
)


def load_uploaded_log():
    """Charge la liste des fichiers déjà uploadés."""
    if os.path.exists(UPLOADED_LOG):
        with open(UPLOADED_LOG, "r") as f:
            return json.load(f)
    return {}


def save_uploaded_log(log):
    """Sauvegarde la liste des fichiers uploadés."""
    with open(UPLOADED_LOG, "w") as f:
        json.dump(log, f, indent=2)


def get_youtube_client():
    """Authentification OAuth2 et retourne le client YouTube."""
    creds = None

    if os.path.exists(TOKEN_FILE):
        creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)

    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            logging.info("🔄 Rafraîchissement du token OAuth...")
            creds.refresh(Request())
        else:
            logging.info("🔐 Connexion OAuth requise (navigateur)...")
            flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS, SCOPES)
            creds = flow.run_local_server(port=0)

        with open(TOKEN_FILE, "w") as f:
            f.write(creds.to_json())

    return build("youtube", "v3", credentials=creds)


def upload_video(youtube, file_path, title):
    """
    Upload un fichier MP4 sur YouTube.
    Retourne True si succès, False sinon.
    Gère les erreurs quota avec retry exponentiel.
    """
    body = {
        "snippet": {
            "title": title,
            "description": f"Upload automatique — {title}",
            "categoryId": CATEGORY_ID,
        },
        "status": {
            "privacyStatus": PRIVACY_STATUS,
        }
    }

    media = MediaFileUpload(
        file_path,
        mimetype="video/mp4",
        resumable=True,    # Upload résumable = sécurisé pour les gros fichiers
        chunksize=10 * 1024 * 1024  # 10 MB par chunk
    )

    for attempt in range(1, MAX_RETRIES + 1):
        try:
            logging.info(f"📤 Upload de '{title}' (tentative {attempt}/{MAX_RETRIES})...")
            request = youtube.videos().insert(
                part="snippet,status",
                body=body,
                media_body=media
            )

            response = None
            while response is None:
                status, response = request.next_chunk()
                if status:
                    pct = int(status.progress() * 100)
                    logging.info(f"   ⏳ Progression : {pct}%")

            video_id = response.get("id")
            logging.info(f"✅ Upload réussi ! https://youtu.be/{video_id}")
            return True

        except HttpError as e:
            code = e.resp.status
            if code in (429, 500, 503):
                wait = RETRY_BASE_DELAY * (2 ** (attempt - 1))
                logging.warning(f"⚠️  Erreur quota/serveur ({code}). Attente {wait}s avant retry...")
                time.sleep(wait)
            else:
                logging.error(f"❌ Erreur HTTP irrécupérable ({code}) : {e}")
                return False

        except Exception as e:
            logging.error(f"❌ Erreur inattendue : {e}")
            return False

    logging.error("❌ Nombre maximum de tentatives atteint. Upload abandonné.")
    return False


def move_to_done(file_path):
    """Déplace le fichier dans le dossier 'done'."""
    os.makedirs(DONE_FOLDER, exist_ok=True)
    dest = os.path.join(DONE_FOLDER, os.path.basename(file_path))
    shutil.move(file_path, dest)
    logging.info(f"📁 Fichier déplacé vers : {dest}")


def scan_and_upload():
    """Scanne le dossier, uploade les nouveaux .mp4, les déplace ensuite."""
    uploaded_log = load_uploaded_log()
    youtube = get_youtube_client()

    mp4_files = sorted([
        f for f in os.listdir(WATCH_FOLDER)
        if f.lower().endswith(".mp4") and os.path.isfile(os.path.join(WATCH_FOLDER, f))
    ])

    if not mp4_files:
        logging.info("📂 Aucun fichier .mp4 trouvé dans le dossier.")
        return

    logging.info(f"🔍 {len(mp4_files)} fichier(s) .mp4 trouvé(s).")

    for filename in mp4_files:
        file_path = os.path.join(WATCH_FOLDER, filename)

        # Déjà uploadé ?
        if filename in uploaded_log:
            logging.info(f"⏭️  '{filename}' déjà uploadé, ignoré.")
            continue

        title = os.path.splitext(filename)[0]  # Nom sans extension

        success = upload_video(youtube, file_path, title)

        if success:
            # Enregistrement dans le log
            uploaded_log[filename] = {
                "uploaded_at": datetime.datetime.now().isoformat(),
                "title": title
            }
            save_uploaded_log(uploaded_log)

            # Déplacement dans done/
            move_to_done(file_path)

            # Délai anti-spam entre les uploads
            logging.info(f"⏸️  Pause de {DELAY_BETWEEN}s avant le prochain upload...")
            time.sleep(DELAY_BETWEEN)
        else:
            logging.error(f"❌ Upload échoué pour '{filename}'. Fichier conservé.")


def main():
    logging.info("🚀 Démarrage de l'uploader YouTube automatique.")
    logging.info(f"   Dossier surveillé : {WATCH_FOLDER}")
    logging.info(f"   Dossier done      : {DONE_FOLDER}")
    logging.info(f"   Délai entre uploads : {DELAY_BETWEEN}s")
    logging.info(f"   Scan toutes les    : {SCAN_INTERVAL}s")

    os.makedirs(WATCH_FOLDER, exist_ok=True)
    os.makedirs(DONE_FOLDER, exist_ok=True)

    while True:
        try:
            scan_and_upload()
        except Exception as e:
            logging.error(f"Erreur dans la boucle principale : {e}")

        logging.info(f"💤 Prochain scan dans {SCAN_INTERVAL}s...\n")
        time.sleep(SCAN_INTERVAL)


if __name__ == "__main__":
    main()
