import os
import cv2
import random
import threading
import tkinter as tk
from tkinter import ttk
import numpy as np
from pydub import AudioSegment
from pydub.silence import detect_nonsilent
import whisper
import subprocess
import math

VIDEO_WIDTH = 1280
VIDEO_HEIGHT = 720
FPS = 30

CHANNELS = {
    "Deep Psychology": {
        "video_folder": r"D:\CANAIS REDE\Deep Psychology",
        "output_folder": r"D:\CANAIS REDE\videos para postar\Deep Psychology",
    },
    "Doodle Vibes": {
        "video_folder": r"D:\CANAIS REDE\Doodle Vibes",
        "output_folder": r"D:\CANAIS REDE\videos para postar\Doodle Vibes",
    },
    "One Infinite": {
        "video_folder": r"D:\CANAIS REDE\One Infinite",
        "output_folder": r"D:\CANAIS REDE\videos para postar\One Infinite",
    },
    "One Realm": {
        "video_folder": r"D:\CANAIS REDE\One Realm",
        "output_folder": r"D:\CANAIS REDE\videos para postar\One Realm",
    },
    "Sequels": {
        "video_folder": r"D:\CANAIS REDE\Sequels",
        "output_folder": r"D:\CANAIS REDE\videos para postar\Sequels",
    },
}

AUDIO_INPUT_FOLDER = r"D:\CANAIS REDE\CENTRAL AUDIO"
AUDIO_BACKGROUND = r"D:\CANAIS REDE\soundfund.mp3"

def remover_silencio(audio_segment, silence_thresh=-50, min_silence_len=500, padding=300):
    nao_silencioso = detect_nonsilent(audio_segment, min_silence_len=min_silence_len, silence_thresh=silence_thresh)
    if not nao_silencioso:
        return audio_segment
    partes = []
    for start, end in nao_silencioso:
        start_pad = max(0, start - padding)
        end_pad = min(len(audio_segment), end + padding)
        partes.append(audio_segment[start_pad:end_pad])
    audio_sem_silencio = partes[0]
    for part in partes[1:]:
        audio_sem_silencio += AudioSegment.silent(duration=150) + part
    return audio_sem_silencio

def load_videos_from_folder(folder):
    video_extensions = (".mp4", ".mov", ".avi", ".mkv", ".wmv")
    files = [f for f in os.listdir(folder) if f.lower().endswith(video_extensions)]
    video_paths = [os.path.join(folder, f) for f in files]
    return video_paths

def resize_frame(frame, width=VIDEO_WIDTH, height=VIDEO_HEIGHT):
    return cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)

def create_video_from_clips(video_path, duration, video_files, fps=FPS, progress_callback=None):
    if not video_files:
        raise ValueError("Nenhum vídeo encontrado para criação do vídeo")

    width = VIDEO_WIDTH
    height = VIDEO_HEIGHT
    total_frames = int(duration * fps)
    out = cv2.VideoWriter(video_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (width, height))

    current_frame_count = 0

    overlay_video_path = r"D:\CANAIS REDE\mmm.mp4"
    cap_overlay = cv2.VideoCapture(overlay_video_path)
    if not cap_overlay.isOpened():
        print(f"Não foi possível abrir o vídeo de overlay: {overlay_video_path}")
        cap_overlay = None

    overlay_fps = cap_overlay.get(cv2.CAP_PROP_FPS) if cap_overlay else fps
    overlay_total_frames = int(cap_overlay.get(cv2.CAP_PROP_FRAME_COUNT)) if cap_overlay else 0
    overlay_current_frame = 0

    amplitude_x = 15
    amplitude_y = 10
    frequency = 0.05

    def frames_from_video(video_filepath):
        cap = cv2.VideoCapture(video_filepath)
        if not cap.isOpened():
            return
        while True:
            ret, frame = cap.read()
            if not ret:
                break
            frame = cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)
            yield frame
        cap.release()

    base_video_file_index = random.randint(0, len(video_files) -1)
    base_video_iterator = iter(frames_from_video(video_files[base_video_file_index]))

    while current_frame_count < total_frames:
        try:
            base_frame = next(base_video_iterator)
        except StopIteration:
            base_video_file_index += 1
            if base_video_file_index >= len(video_files):
                base_video_file_index = 0
            base_video_iterator = iter(frames_from_video(video_files[base_video_file_index]))
            base_frame = next(base_video_iterator)

        if cap_overlay:
            ret_ov, overlay_frame = cap_overlay.read()
            if not ret_ov:
                cap_overlay.set(cv2.CAP_PROP_POS_FRAMES, 0)
                ret_ov, overlay_frame = cap_overlay.read()
            if ret_ov:
                overlay_frame = cv2.resize(overlay_frame, (width, height), interpolation=cv2.INTER_AREA)

                dx = int(amplitude_x * math.sin(frequency * current_frame_count))
                dy = int(amplitude_y * math.cos(frequency * current_frame_count))

                overlay_moved = np.zeros_like(overlay_frame)
                h, w = overlay_frame.shape[:2]

                x_start_overlay = max(0, -dx)
                x_end_overlay = w - max(0, dx)
                y_start_overlay = max(0, -dy)
                y_end_overlay = h - max(0, dy)

                x_start_base = max(0, dx)
                x_end_base = x_start_base + (x_end_overlay - x_start_overlay)
                y_start_base = max(0, dy)
                y_end_base = y_start_base + (y_end_overlay - y_start_overlay)

                overlay_moved[y_start_base:y_end_base, x_start_base:x_end_base] = overlay_frame[y_start_overlay:y_end_overlay, x_start_overlay:x_end_overlay]

                blended = cv2.addWeighted(overlay_moved, 0.5, base_frame, 0.5, 0)
            else:
                blended = base_frame
        else:
            blended = base_frame

        out.write(blended)
        current_frame_count += 1
        if progress_callback:
            progress_callback(current_frame_count, total_frames)

    if cap_overlay:
        cap_overlay.release()
    out.release()

def merge_audio_with_video(video_path, audio_path, output_path, audio_background_path=None):
    audio1 = AudioSegment.from_file(audio_path).set_channels(2)

    if audio_background_path and os.path.exists(audio_background_path):
        audio2 = AudioSegment.from_file(audio_background_path).set_channels(2)
        audio2 = audio2 - 15
        if len(audio2) < len(audio1):
            audio2 *= (len(audio1) // len(audio2) + 1)
        audio2 = audio2[:len(audio1)]
        combined = audio1.overlay(audio2)
    else:
        combined = audio1

    temp_audio_path = "temp_combined_audio.mp3"
    combined.export(temp_audio_path, format="mp3")

    command = [
        "ffmpeg",
        "-y",
        "-i", video_path,
        "-i", temp_audio_path,
        "-c:v", "copy",
        "-c:a", "aac",
        "-shortest",
        output_path
    ]
    subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
    if os.path.exists(temp_audio_path):
        os.remove(temp_audio_path)

def selecionar_canal_por_balanceamento():
    counts = {}
    for channel_name, paths in CHANNELS.items():
        folder = paths["output_folder"]
        try:
            files = [f for f in os.listdir(folder) if f.lower().endswith(".mp4")]
            counts[channel_name] = len(files)
        except Exception:
            counts[channel_name] = 0

    if all(v == 0 for v in counts.values()):
        return random.choice(list(CHANNELS.keys()))

    min_count = min(counts.values())
    candidatos = [ch for ch, c in counts.items() if c == min_count]
    return random.choice(candidatos)

def criar_video_com_interface():
    root = tk.Tk()
    root.title("Criador de Vídeo com vídeos e áudio")
    root.geometry("600x250")

    tk.Label(root, text=f"Pasta de entrada Áudios: {AUDIO_INPUT_FOLDER}").pack(pady=7)
    tk.Label(root, text="Coloque arquivos de áudio (.mp3, .wav, .m4a) na pasta acima para iniciar a produção automática.").pack()

    progress_var = tk.IntVar()
    progress_bar = ttk.Progressbar(root, maximum=100, variable=progress_var, length=550)
    progress_bar.pack(pady=7)

    progress_label = tk.Label(root, text="Aguardando arquivos na fila...")
    progress_label.pack(pady=7)

    processing_lock = threading.Lock()
    queue_audios = []
    processing = False

    model = whisper.load_model("small")

    def update_progress_ui(atual, total):
        pct = int(atual / total * 100)
        progress_var.set(pct)
        progress_label.config(text=f"Progresso: {pct}%")
        root.update_idletasks()

    def process_audio_file(audio_path):
        nonlocal processing
        try:
            canal = selecionar_canal_por_balanceamento()
            video_folder = CHANNELS[canal]['video_folder']
            output_folder = CHANNELS[canal]['output_folder']
            if not os.path.exists(output_folder):
                os.makedirs(output_folder)

            videos = load_videos_from_folder(video_folder)
            if not videos:
                print(f"Nenhum vídeo válido encontrado em {video_folder}, pulando {os.path.basename(audio_path)}")
                with processing_lock:
                    processing = False
                root.after(100, check_and_start_process)
                return

            progress_var.set(0)
            progress_label.config(text=f"Processando: {os.path.basename(audio_path)} | Canal: {canal}")
            root.update_idletasks()

            audio = AudioSegment.from_file(audio_path)
            silence_thresh = audio.dBFS - 14
            audio_sem_silencio = remover_silencio(audio, silence_thresh=silence_thresh, min_silence_len=400, padding=300)
            temp_audio_clean = "temp_audio_clean.mp3"
            audio_sem_silencio.export(temp_audio_clean, format="mp3")

            duration = audio_sem_silencio.duration_seconds
            base_name = os.path.splitext(os.path.basename(audio_path))[0]
            temp_video = base_name + "_temp.mp4"
            video_final = os.path.join(output_folder, f"{base_name}.mp4")

            create_video_from_clips(temp_video, duration, videos, fps=FPS, progress_callback=update_progress_ui)

            merge_audio_with_video(temp_video, temp_audio_clean, video_final, audio_background_path=AUDIO_BACKGROUND)

            if os.path.exists(temp_video):
                os.remove(temp_video)
            if os.path.exists(temp_audio_clean):
                os.remove(temp_audio_clean)
            try:
                if os.path.exists(audio_path):
                    os.remove(audio_path)
            except Exception as e:
                print(f"Erro ao remover arquivo de áudio original: {e}")

        except Exception as e:
            print(f"Erro ao criar vídeo para {audio_path}: {e}")
        finally:
            with processing_lock:
                processing = False
            root.after(100, check_and_start_process)

    def check_and_start_process():
        nonlocal processing
        with processing_lock:
            if processing or not queue_audios:
                if not queue_audios:
                    progress_label.config(text="Fila vazia, aguardando novos arquivos na pasta:\n" + AUDIO_INPUT_FOLDER)
                return
            next_audio = queue_audios.pop(0)
            processing = True

        threading.Thread(target=process_audio_file, args=(next_audio,), daemon=True).start()

    def scan_for_new_audios():
        try:
            current_files = [f for f in os.listdir(AUDIO_INPUT_FOLDER) if f.lower().endswith((".mp3", ".wav", ".m4a"))]
            abs_files = [os.path.join(AUDIO_INPUT_FOLDER, f) for f in current_files]
        except Exception as e:
            print(f"Erro ao listar pasta de áudio: {e}")
            abs_files = []

        with processing_lock:
            fila_set = set(queue_audios)
            for fpath in abs_files:
                if fpath not in fila_set and os.path.isfile(fpath):
                    queue_audios.append(fpath)

    def periodic_scan():
        try:
            scan_for_new_audios()
            check_and_start_process()
        except Exception as e:
            print(f"Erro no scan ou start do processo: {e}")
        root.after(5000, periodic_scan)

    periodic_scan()
    root.mainloop()

if __name__ == "__main__":
    criar_video_com_interface() . chat aumente mais o som de fundo . me de o codigo completo já com essa alteração . além disse coloque na interface para se eu quiser eu posso travar alguma pasta para não ser mas ultilizada pelo sistema e verificar e mandar para lá exemplo se não quero que ele crie videos para um canal especifico eu travo e ele passa a distribuir só nos outros