#!/usr/bin/env python3
"""Upload a video to your own YouTube channel and schedule it. From the Career with Sukrit guide.

Put client_secret.json next to this file, then:
  python3 yt_schedule.py --check
  python3 yt_schedule.py my_video.mp4 --title "My title #Shorts" --at "2026-12-01 19:00"
Add --dry-run to preview without uploading. Times are in --tz (default Asia/Kolkata).
Keep client_secret.json and token.json private. Anyone with them can post to your channel.
"""
import argparse, os, sys
from datetime import datetime, timezone
from zoneinfo import ZoneInfo

HERE = os.path.dirname(os.path.abspath(__file__))
SECRET, TOKEN = os.path.join(HERE, "client_secret.json"), os.path.join(HERE, "token.json")
SCOPES = ["https://www.googleapis.com/auth/youtube.upload", "https://www.googleapis.com/auth/youtube"]


def publish_at(text, tz):
    """'2026-12-01 19:00' in tz -> UTC string for YouTube. Must be in the future."""
    when = datetime.strptime(text, "%Y-%m-%d %H:%M").replace(tzinfo=ZoneInfo(tz)).astimezone(timezone.utc)
    if when <= datetime.now(timezone.utc):
        sys.exit(f"--at {text} is in the past. Pick a future time.")
    return when.strftime("%Y-%m-%dT%H:%M:%SZ")


def youtube():
    from google.auth.transport.requests import Request
    from google.oauth2.credentials import Credentials
    from google_auth_oauthlib.flow import InstalledAppFlow
    from googleapiclient.discovery import build
    creds = Credentials.from_authorized_user_file(TOKEN, SCOPES) if os.path.exists(TOKEN) else None
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            if not os.path.exists(SECRET):
                sys.exit("client_secret.json not found next to this script. See the guide, step 6.")
            creds = InstalledAppFlow.from_client_secrets_file(SECRET, SCOPES).run_local_server(port=0)
        with open(TOKEN, "w") as f:
            f.write(creds.to_json())
    return build("youtube", "v3", credentials=creds)


def main():
    p = argparse.ArgumentParser()
    p.add_argument("video", nargs="?")
    p.add_argument("--title")
    p.add_argument("--description", default="")
    p.add_argument("--tags", default="", help="comma separated")
    p.add_argument("--at", help='local time, e.g. "2026-12-01 19:00"')
    p.add_argument("--tz", default="Asia/Kolkata")
    p.add_argument("--category", default="27", help="27 = Education, 22 = People & Blogs")
    p.add_argument("--check", action="store_true", help="sign in and show your channel, upload nothing")
    p.add_argument("--dry-run", action="store_true")
    a = p.parse_args()

    if a.check:
        me = youtube().channels().list(part="snippet", mine=True).execute()["items"][0]
        print("Connected to channel:", me["snippet"]["title"])
        return
    if not (a.video and a.title and a.at):
        p.error("video, --title and --at are needed to schedule")
    if not os.path.isfile(a.video):
        sys.exit(f"Video not found: {a.video}")
    at = publish_at(a.at, a.tz)
    body = {"snippet": {"title": a.title[:100], "description": a.description, "categoryId": a.category,
                        "tags": [t.strip() for t in a.tags.split(",") if t.strip()]},
            "status": {"privacyStatus": "private", "publishAt": at, "selfDeclaredMadeForKids": False}}
    print(f"{a.video} goes public at {at} UTC: {a.title[:100]}")
    if a.dry_run:
        return
    from googleapiclient.http import MediaFileUpload
    req = youtube().videos().insert(part="snippet,status", body=body,
                                    media_body=MediaFileUpload(a.video, chunksize=-1, resumable=True))
    res = None
    while res is None:
        _, res = req.next_chunk()
    print("Scheduled: https://youtu.be/" + res["id"])


if __name__ == "__main__":
    main()
