import tkinter as tk
from tkinter import messagebox
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from google.auth.transport.requests import Request
import os
import pickle
from datetime import datetime, timedelta
import pytz
import random
import time

# --- CONFIGURAÇÕES ---

TIMEZONE_BR = pytz.timezone("America/Sao_Paulo")

CREDENCIAIS_PATH = r"D:\CANAIS REDE\CREDENCIAL"

CREDENCIAIS_VIDEOS_MAP = {
    "Deep.pickle": r"D:\CANAIS REDE\videos para postar\Deep Psychology",
    "Doodle.pickle": r"D:\CANAIS REDE\videos para postar\Doodle Vibes",
    "OneInfinite.pickle": r"D:\CANAIS REDE\videos para postar\One Infinite",
    "OneRealm.pickle": r"D:\CANAIS REDE\videos para postar\One Realm",
    "Sequels.pickle": r"D:\CANAIS REDE\videos para postar\Sequels"
}

THUMBNAILS_FOLDER = r"D:\CANAIS REDE\thubnail"

DEFAULT_DESCRIPTION = """
🔮 Is the Universe Trying to Tell You Something? Discover the 4 Signs You're Destined to Be with Someone | Carl Jung’s Teachings

Have you ever met someone and instantly felt there was something deeper going on? Like it wasn’t just a coincidence?

In this video, we dive into the profound insights of psychologist Carl Jung and reveal the 4 spiritual and psychological signs that the universe may be aligning your life with another person’s.
From repeated "coincidences" to deep emotional connections and inner transformations, Jung believed that synchronicity and the collective unconscious could guide us to the relationships that truly matter.

If you've ever wondered whether a certain person came into your life for a reason — this video will help you understand why.

👉 Watch until the end to discover how to recognize these signs and what they might mean for your destiny and love life.

✨ Don't forget to like, subscribe, and turn on notifications for more content on Carl Jung, synchronicity, destiny, and deep psychology.

#carljung  #synchronicity  #soulmates  #jungianpsychology  #signsfromtheuniverse  #destiny2  #spirituallove  #JungLove #spiritualawakening  #psychologyoflove  #theone  #universesigns  #deepconnection  #soulconnection  #relationships  #divinetiming 

Keywords (SEO):
Carl Jung soulmate signs, synchronicity in love, Jungian psychology relationships, signs you're meant to be with someone, psychological signs of love, spiritual signs universe, destiny love connection, Carl Jung synchronicity meaning, twin flame signs, universe bringing someone back.
"""

DEFAULT_TAGS = [
    "carl gustav jung","carl gustv jung","carl jung","carl jung arquetipos","carl jung explained",
    "carl jung la sombra","carl jung lecture","carl jung mindset","carl jung philosophy",
    "carl jung psychology","carl jung quotes","carl jung shadow","carl jung shadow work",
    "carl jung teachings","carl jung the red book","carl jung theory","carl jung warning",
    "carl jung wholeness","red book carl jung","the red book carl jung"
]

# --- FUNÇÕES ---

def load_credentials(path_pickle):
    try:
        with open(path_pickle, "rb") as f:
            creds = pickle.load(f)
        if creds.expired and creds.refresh_token:
            creds.refresh(Request())
        return creds
    except Exception as e:
        print(f"Erro ao carregar credencial {path_pickle}: {e}")
        return None

def upload_video(creds, title, description, tags, video_path, thumb_path, privacy_status="private", publish_at=None):
    youtube = build("youtube", "v3", credentials=creds)
    body = {
        "snippet": {
            "title": title,
            "description": description,
            "tags": tags,
            "categoryId": "22"  # categoria default, pode ajustar se quiser
        },
        "status": {
            "privacyStatus": privacy_status
        }
    }

    if publish_at:
        # ISO 8601 + UTC
        dt_obj = datetime.fromisoformat(publish_at)
        dt_utc = dt_obj.astimezone(pytz.utc)
        body["status"]["publishAt"] = dt_utc.isoformat()

    media = MediaFileUpload(video_path, mimetype="video/mp4", chunksize=-1, resumable=True)

    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:
            print(f"Upload {int(status.progress() * 100)}% do vídeo {os.path.basename(video_path)}")

    video_id = response["id"]

    if thumb_path and os.path.exists(thumb_path):
        try:
            youtube.thumbnails().set(videoId=video_id, media_body=MediaFileUpload(thumb_path)).execute()
        except Exception as e:
            print(f"Não foi possível enviar thumbnail: {e}")

    print(f"Upload finalizado: {video_id}")
    return video_id

def obter_videos(pasta, qtd):
    if not os.path.isdir(pasta):
        return []
    vids = [os.path.join(pasta, f) for f in os.listdir(pasta) if f.lower().endswith(".mp4")]
    vids.sort(key=lambda f: os.path.getctime(f))
    if len(vids) < qtd:
        return []
    return vids[:qtd]

def obter_thumbnails_disponiveis():
    if not os.path.isdir(THUMBNAILS_FOLDER):
        return []
    thumbs = [os.path.join(THUMBNAILS_FOLDER, f) for f in os.listdir(THUMBNAILS_FOLDER) if f.lower().endswith((".jpg", ".jpeg", ".png"))]
    return thumbs

def remover_arquivo(caminho):
    try:
        os.remove(caminho)
    except Exception as e:
        print(f"Erro ao remover arquivo {caminho}: {e}")

def agendar_e_enviar_videos(data_inicio_str, hora_inicio_str, qtd_por_canal):
    # parse data/hora
    try:
        data_inicio = datetime.strptime(data_inicio_str, "%d/%m/%Y")
        hora_inicio = datetime.strptime(hora_inicio_str, "%H:%M").time()
        dt_inicio = datetime.combine(data_inicio, hora_inicio)
        dt_inicio = TIMEZONE_BR.localize(dt_inicio)
    except Exception as e:
        messagebox.showerror("Erro", f"Formato de data/hora inválido: {e}")
        return

    credenciais_validas = {}
    credenciais_invalidas = []
    for nome_pickle, pasta_vid in CREDENCIAIS_VIDEOS_MAP.items():
        caminho_cred = os.path.join(CREDENCIAIS_PATH, nome_pickle)
        creds_obj = load_credentials(caminho_cred)
        if creds_obj is None:
            credenciais_invalidas.append(nome_pickle)
        else:
            canal = nome_pickle.split(".")[0]
            credenciais_validas[nome_pickle] = (creds_obj, canal, pasta_vid)

    if credenciais_invalidas:
        messagebox.showerror("Credenciais inválidas ou não carregadas", f"Arquivos .pickle inválidos:\n" + "\n".join(credenciais_invalidas))
        return

    # verificar vídeos suficientes
    insuficientes = []
    vids_por_canal = {}
    for nome_pickle, (creds_obj, canal, pasta_vid) in credenciais_validas.items():
        vids = obter_videos(pasta_vid, qtd_por_canal)
        if not vids:
            insuficientes.append(f"{nome_pickle} ({pasta_vid})")
        else:
            vids_por_canal[nome_pickle] = vids

    if insuficientes:
        messagebox.showwarning("Vídeos insuficientes", f"Não há vídeos suficientes nos canais:\n" + "\n".join(insuficientes))
        return

    thumbs = obter_thumbnails_disponiveis()
    if len(thumbs) < qtd_por_canal * len(credenciais_validas):
        messagebox.showwarning("Thumbs insuficientes", f"Thumbnails disponíveis ({len(thumbs)}) são menos que necessários ({qtd_por_canal * len(credenciais_validas)})")
        return

    thumbs_disponiveis = thumbs.copy()
    horarios = [dt_inicio + timedelta(hours=i) for i in range(qtd_por_canal)]

    enviados = 0

    for i in range(qtd_por_canal):
        for nome_pickle, (creds_obj, canal, pasta_vid) in credenciais_validas.items():
            video_path = vids_por_canal[nome_pickle][i]

            if not thumbs_disponiveis:
                messagebox.showerror("Erro", "Acabaram thumbnails durante envio, abortando.")
                return
            thumb_path = random.choice(thumbs_disponiveis)
            thumbs_disponiveis.remove(thumb_path)

            dt_postagem = horarios[i]
            publish_at_iso = dt_postagem.isoformat()

            titulo = os.path.splitext(os.path.basename(video_path))[0]

            try:
                print(f"Iniciando upload: Canal {canal}, vídeo {titulo} agendado para {publish_at_iso}")
                video_id = upload_video(
                    creds=creds_obj,
                    title=titulo,
                    description=DEFAULT_DESCRIPTION,
                    tags=DEFAULT_TAGS,
                    video_path=video_path,
                    thumb_path=thumb_path,
                    privacy_status="private",
                    publish_at=publish_at_iso
                )
                if video_id:
                    # apagar arquivos somente após sucesso:
                    remover_arquivo(video_path)
                    remover_arquivo(thumb_path)
                    enviados += 1
                    print(f"Upload completado: {video_id}")
                    
                    # pequena pausa para evitar problemas de quota/erro de API:
                    time.sleep(10)
                else:
                    messagebox.showerror("Erro", f"Falha ao enviar vídeo {titulo}")
                    return
            except Exception as e:
                messagebox.showerror("Erro no upload", f"Erro ao enviar vídeo {titulo}: {e}")
                return

    messagebox.showinfo("Sucesso", f"{enviados} vídeos agendados e enviados para {len(credenciais_validas)} canais.")

# --- INTERFACE ---

def atualizar_status_credenciais_ui():
    for widget in frame_credenciais_status.winfo_children():
        widget.destroy()
    for nome_pickle in CREDENCIAIS_VIDEOS_MAP.keys():
        caminho_cred = os.path.join(CREDENCIAIS_PATH, nome_pickle)
        if not os.path.exists(caminho_cred):
            cor = "red"
            texto = f"{nome_pickle} - Arquivo .pickle não encontrado"
        else:
            creds_obj = load_credentials(caminho_cred)
            if creds_obj is None:
                cor = "red"
                texto = f"{nome_pickle} - Credencial inválida"
            else:
                cor = "green"
                texto = f"{nome_pickle} - Credencial válida"
        lbl = tk.Label(frame_credenciais_status, text=texto, fg=cor, font=("Arial", 12, "bold"))
        lbl.pack(anchor="w")

root = tk.Tk()
root.title("Agendador Carl Jung - Multi Canais com Upload")
root.geometry("700x500")

frame_credenciais_status = tk.LabelFrame(root, text="Status das Credenciais")
frame_credenciais_status.pack(fill="x", padx=10, pady=10)

atualizar_status_credenciais_ui()

frame_conf = tk.LabelFrame(root, text="Configurar agendamento")
frame_conf.pack(fill="x", padx=10, pady=10)

tk.Label(frame_conf, text="Data de início (dd/mm/aaaa):").grid(row=0, column=0, sticky="w", padx=5, pady=5)
entrada_data = tk.Entry(frame_conf)
entrada_data.grid(row=0, column=1, sticky="w", padx=5, pady=5)
entrada_data.insert(0, datetime.now().strftime("%d/%m/%Y"))

tk.Label(frame_conf, text="Hora de início (HH:MM):").grid(row=1, column=0, sticky="w", padx=5, pady=5)
entrada_hora = tk.Entry(frame_conf)
entrada_hora.grid(row=1, column=1, sticky="w", padx=5, pady=5)
entrada_hora.insert(0, "03:00")

tk.Label(frame_conf, text="Quantidade de vídeos por canal:").grid(row=2, column=0, sticky="w", padx=5, pady=5)
entrada_qtd = tk.Entry(frame_conf, width=5)
entrada_qtd.grid(row=2, column=1, sticky="w", padx=5, pady=5)
entrada_qtd.insert(0, "6")

def on_agendar_click():
    data = entrada_data.get()
    hora = entrada_hora.get()
    try:
        qtd = int(entrada_qtd.get())
        if qtd <= 0:
            raise ValueError()
    except:
        messagebox.showwarning("Atenção", "Quantidade inválida. Informe número inteiro positivo.")
        return
    agendar_e_enviar_videos(data, hora, qtd)

btn_agendar = tk.Button(root, text="Agendar e Enviar vídeos para todos os canais", command=on_agendar_click)
btn_agendar.pack(pady=20)

root.mainloop() . chat faça as seguintes alterações ele não posta mas os 6 videos ele me da a opção de escolher quantos videos ele quer que eu escolha para posta para cada canal individualmente de 0 a 12 . segue sendo no mesmo estilo de programar só me de a opção de escolher quantos para quais canais