"""
youtube_auto_upload.py
----------------------
Upload automatique de vidéos .mp4 vers YouTube depuis un dossier.

Fonctions :
- Scan d'un dossier
- Upload séquentiel (1 par 1)
- Limite quotidienne d'uploads
- Anti-doublons
- Retry en cas d'erreur quota
- Aucun déplacement de fichier (les vidéos restent en place)

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

import os
import time
import json
import logging
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

# ───────────────────────── CONFIG ─────────────────────────

WATCH_FOLDER = "/home/videos/processed/ghostofatale"
CLIENT_SECRETS = "client_secrets.json"
TOKEN_FILE = "token.json"

UPLOADED_LOG = "uploaded.json"
UPLOAD_DAY_LOG = "daily_uploads.json"

DELAY_BETWEEN = 120          # pause entre uploads (sec)
SCAN_INTERVAL = 300          # scan dossier (sec)

MAX_RETRIES = 5
RETRY_BASE_DELAY = 30

MAX_UPLOADS_PER_DAY = 20     # limite quotidienne

PRIVACY_STATUS = "private"
CATEGORY_ID = "20"

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

# ───────────────────────── LOGGING ─────────────────────────

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

# ───────────────────────── STORAGE ─────────────────────────

def load_json(path):
    if os.path.exists(path):
        with open(path, "r") as f:
            return json.load(f)
    return {}

def save_json(path, data):
    with open(path, "w") as f:
        json.dump(data, f, indent=2)

# ───────────────────────── DAILY LIMIT ─────────────────────────

def can_upload_today(log):
    today = str(datetime.date.today())
    return log.get(today, 0) < MAX_UPLOADS_PER_DAY

def increment_daily(log):
    today = str(datetime.date.today())
    log[today] = log.get(today, 0) + 1
    return log

# ───────────────────────── YOUTUBE AUTH ─────────────────────────

def get_youtube_client():
    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:
            creds.refresh(Request())
        else:
            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)

# ───────────────────────── UPLOAD ─────────────────────────

def upload_video(youtube, file_path, title):

    body = {
        "snippet": {
            "title": title,
            "description": f"Auto upload — {title}",
            "categoryId": CATEGORY_ID,
        },
        "status": {
            "privacyStatus": PRIVACY_STATUS,
        }
    }

    media = MediaFileUpload(
        file_path,
        mimetype="video/mp4",
        resumable=True,
        chunksize=10 * 1024 * 1024
    )

    for attempt in range(1, MAX_RETRIES + 1):
        try:
            logging.info(f"📤 Upload: {title} ({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"   ⏳ {pct}%")

            video_id = response.get("id")
            logging.info(f"✅ OK 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"⚠️ quota error {code}, wait {wait}s")
                time.sleep(wait)
            else:
                logging.error(f"❌ HTTP error {code}")
                return False

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

    return False

# ───────────────────────── CORE LOOP ─────────────────────────

def scan_and_upload():

    uploaded_log = load_json(UPLOADED_LOG)
    daily_log = load_json(UPLOAD_DAY_LOG)

    youtube = get_youtube_client()

    if not can_upload_today(daily_log):
        logging.info("⛔ quota quotidienne atteinte")
        return

    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 files:
        logging.info("📂 aucun fichier")
        return

    logging.info(f"🔍 {len(files)} fichiers détectés")

    for filename in files:

        if filename in uploaded_log:
            logging.info(f"⏭️ skip {filename}")
            continue

        if not can_upload_today(daily_log):
            logging.info("⛔ stop quota jour atteint")
            break

        file_path = os.path.join(WATCH_FOLDER, filename)
        title = os.path.splitext(filename)[0]

        success = upload_video(youtube, file_path, title)

        if success:
            uploaded_log[filename] = {
                "date": datetime.datetime.now().isoformat(),
                "title": title
            }
            save_json(UPLOADED_LOG, uploaded_log)

            daily_log = increment_daily(daily_log)
            save_json(UPLOAD_DAY_LOG, daily_log)

            logging.info(f"⏸️ pause {DELAY_BETWEEN}s")
            time.sleep(DELAY_BETWEEN)

# ───────────────────────── MAIN ─────────────────────────

def main():
    logging.info("🚀 YouTube auto uploader started")
    os.makedirs(WATCH_FOLDER, exist_ok=True)

    while True:
        try:
            scan_and_upload()
        except Exception as e:
            logging.error(f"loop error: {e}")

        logging.info(f"💤 sleep {SCAN_INTERVAL}s")
        time.sleep(SCAN_INTERVAL)

# ───────────────────────── START ─────────────────────────

if __name__ == "__main__":
    main()