#!/usr/bin/env python3
"""
Video Transcriber - macOS App
Transcreve vídeos do YouTube usando Whisper AI
Interface usando tkinter nativo com tema escuro
"""

import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import threading
import os
import re
import json
from datetime import datetime
from pathlib import Path
from typing import Optional

# Diretórios
APP_DIR = Path(__file__).parent
TRANSCRIPTIONS_DIR = APP_DIR / "transcriptions"
LOGS_DIR = APP_DIR / "logs"

# Criar diretórios se não existirem
TRANSCRIPTIONS_DIR.mkdir(exist_ok=True)
LOGS_DIR.mkdir(exist_ok=True)

# Cores do tema escuro
COLORS = {
    "bg": "#1e1e1e",
    "bg_secondary": "#2d2d2d",
    "bg_tertiary": "#3c3c3c",
    "fg": "#ffffff",
    "fg_secondary": "#a0a0a0",
    "accent": "#007AFF",
    "accent_hover": "#0056b3",
    "success": "#28a745",
    "error": "#dc3545",
    "border": "#404040"
}


class VideoTranscriberApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Video Transcriber")
        self.root.geometry("900x750")
        self.root.minsize(800, 600)
        self.root.configure(bg=COLORS["bg"])

        # Variáveis
        self.is_transcribing = False
        self.model_var = tk.StringVar(value="base")
        self.lang_var = tk.StringVar(value="auto")

        # Configurar estilo
        self.setup_styles()

        # Criar UI
        self.create_ui()

    def setup_styles(self):
        """Configura estilos ttk para tema escuro"""
        style = ttk.Style()
        style.theme_use('clam')

        # Frame
        style.configure("Dark.TFrame", background=COLORS["bg"])
        style.configure("Card.TFrame", background=COLORS["bg_secondary"])

        # Label
        style.configure("Dark.TLabel",
                       background=COLORS["bg"],
                       foreground=COLORS["fg"],
                       font=("SF Pro Display", 13))

        style.configure("Title.TLabel",
                       background=COLORS["bg"],
                       foreground=COLORS["fg"],
                       font=("SF Pro Display", 24, "bold"))

        style.configure("Subtitle.TLabel",
                       background=COLORS["bg"],
                       foreground=COLORS["fg_secondary"],
                       font=("SF Pro Display", 12))

        style.configure("Card.TLabel",
                       background=COLORS["bg_secondary"],
                       foreground=COLORS["fg"],
                       font=("SF Pro Display", 13))

        style.configure("CardTitle.TLabel",
                       background=COLORS["bg_secondary"],
                       foreground=COLORS["fg"],
                       font=("SF Pro Display", 13, "bold"))

        # Button
        style.configure("Accent.TButton",
                       background=COLORS["accent"],
                       foreground=COLORS["fg"],
                       font=("SF Pro Display", 14, "bold"),
                       padding=(20, 12))

        style.map("Accent.TButton",
                 background=[("active", COLORS["accent_hover"])])

        # Combobox
        style.configure("Dark.TCombobox",
                       fieldbackground=COLORS["bg_tertiary"],
                       background=COLORS["bg_tertiary"],
                       foreground=COLORS["fg"],
                       arrowcolor=COLORS["fg"])

        # Progressbar
        style.configure("Dark.Horizontal.TProgressbar",
                       background=COLORS["accent"],
                       troughcolor=COLORS["bg_tertiary"])

    def create_ui(self):
        """Cria interface do usuário"""
        # Container principal
        main_frame = ttk.Frame(self.root, style="Dark.TFrame")
        main_frame.pack(fill="both", expand=True, padx=25, pady=25)

        # Header
        self.create_header(main_frame)

        # URL Input
        self.create_url_section(main_frame)

        # Options
        self.create_options_section(main_frame)

        # Transcribe Button
        self.create_action_section(main_frame)

        # Output
        self.create_output_section(main_frame)

        # Footer
        self.create_footer(main_frame)

    def create_header(self, parent):
        """Cria header com título"""
        header_frame = ttk.Frame(parent, style="Dark.TFrame")
        header_frame.pack(fill="x", pady=(0, 20))

        title = ttk.Label(header_frame, text="Video Transcriber", style="Title.TLabel")
        title.pack(side="left")

        subtitle = ttk.Label(header_frame, text="Powered by OpenAI Whisper", style="Subtitle.TLabel")
        subtitle.pack(side="left", padx=(15, 0), pady=(10, 0))

    def create_url_section(self, parent):
        """Cria seção de input da URL"""
        card = self.create_card(parent)

        # Label
        label = ttk.Label(card, text="YouTube URL:", style="CardTitle.TLabel")
        label.pack(anchor="w", pady=(0, 8))

        # Input frame
        input_frame = ttk.Frame(card, style="Card.TFrame")
        input_frame.pack(fill="x")

        # Entry
        self.url_entry = tk.Entry(
            input_frame,
            font=("SF Pro Display", 14),
            bg=COLORS["bg_tertiary"],
            fg=COLORS["fg"],
            insertbackground=COLORS["fg"],
            relief="flat",
            highlightthickness=1,
            highlightcolor=COLORS["accent"],
            highlightbackground=COLORS["border"]
        )
        self.url_entry.pack(side="left", fill="x", expand=True, ipady=10, padx=(0, 10))

        # Paste button
        paste_btn = tk.Button(
            input_frame,
            text="Colar",
            font=("SF Pro Display", 12),
            bg=COLORS["bg_tertiary"],
            fg=COLORS["fg"],
            activebackground=COLORS["accent"],
            activeforeground=COLORS["fg"],
            relief="flat",
            cursor="hand2",
            command=self.paste_url
        )
        paste_btn.pack(side="right", ipadx=15, ipady=8)

    def create_options_section(self, parent):
        """Cria seção de opções"""
        card = self.create_card(parent)

        options_frame = ttk.Frame(card, style="Card.TFrame")
        options_frame.pack(fill="x")

        # Model selection
        model_frame = ttk.Frame(options_frame, style="Card.TFrame")
        model_frame.pack(side="left", fill="x", expand=True)

        model_label = ttk.Label(model_frame, text="Modelo Whisper:", style="CardTitle.TLabel")
        model_label.pack(anchor="w")

        self.model_combo = ttk.Combobox(
            model_frame,
            textvariable=self.model_var,
            values=["tiny", "base", "small", "medium", "large"],
            state="readonly",
            width=15,
            font=("SF Pro Display", 12)
        )
        self.model_combo.pack(anchor="w", pady=(5, 0))

        model_info = ttk.Label(
            model_frame,
            text="tiny: Rápido | base: Balanceado | medium: Preciso",
            style="Subtitle.TLabel"
        )
        model_info.configure(background=COLORS["bg_secondary"])
        model_info.pack(anchor="w", pady=(5, 0))

        # Language selection
        lang_frame = ttk.Frame(options_frame, style="Card.TFrame")
        lang_frame.pack(side="right", padx=(20, 0))

        lang_label = ttk.Label(lang_frame, text="Idioma:", style="CardTitle.TLabel")
        lang_label.pack(anchor="w")

        self.lang_combo = ttk.Combobox(
            lang_frame,
            textvariable=self.lang_var,
            values=["auto", "pt", "en", "es", "fr", "de", "it", "ja", "ko", "zh"],
            state="readonly",
            width=12,
            font=("SF Pro Display", 12)
        )
        self.lang_combo.pack(anchor="w", pady=(5, 0))

    def create_action_section(self, parent):
        """Cria seção de ação (botão e progresso)"""
        card = self.create_card(parent)

        # Transcribe button
        self.transcribe_btn = tk.Button(
            card,
            text="Transcrever",
            font=("SF Pro Display", 16, "bold"),
            bg=COLORS["accent"],
            fg=COLORS["fg"],
            activebackground=COLORS["accent_hover"],
            activeforeground=COLORS["fg"],
            relief="flat",
            cursor="hand2",
            command=self.start_transcription
        )
        self.transcribe_btn.pack(fill="x", ipady=12, pady=(0, 15))

        # Progress bar
        self.progress = ttk.Progressbar(
            card,
            style="Dark.Horizontal.TProgressbar",
            mode="determinate",
            length=100
        )
        self.progress.pack(fill="x", pady=(0, 10))

        # Status label
        self.status_var = tk.StringVar(value="Pronto para transcrever")
        self.status_label = ttk.Label(
            card,
            textvariable=self.status_var,
            style="Subtitle.TLabel"
        )
        self.status_label.configure(background=COLORS["bg_secondary"])
        self.status_label.pack(anchor="w")

    def create_output_section(self, parent):
        """Cria seção de output"""
        card = self.create_card(parent, expand=True)

        # Header
        output_header = ttk.Frame(card, style="Card.TFrame")
        output_header.pack(fill="x", pady=(0, 10))

        output_label = ttk.Label(output_header, text="Transcrição:", style="CardTitle.TLabel")
        output_label.pack(side="left")

        # Buttons
        btn_frame = ttk.Frame(output_header, style="Card.TFrame")
        btn_frame.pack(side="right")

        open_btn = tk.Button(
            btn_frame,
            text="Abrir Pasta",
            font=("SF Pro Display", 11),
            bg=COLORS["bg_tertiary"],
            fg=COLORS["fg"],
            activebackground=COLORS["accent"],
            activeforeground=COLORS["fg"],
            relief="flat",
            cursor="hand2",
            command=self.open_folder
        )
        open_btn.pack(side="left", ipadx=10, ipady=5, padx=(0, 8))

        copy_btn = tk.Button(
            btn_frame,
            text="Copiar",
            font=("SF Pro Display", 11),
            bg=COLORS["bg_tertiary"],
            fg=COLORS["fg"],
            activebackground=COLORS["accent"],
            activeforeground=COLORS["fg"],
            relief="flat",
            cursor="hand2",
            command=self.copy_transcript
        )
        copy_btn.pack(side="left", ipadx=10, ipady=5)

        # Text area
        self.output_text = scrolledtext.ScrolledText(
            card,
            font=("SF Mono", 12),
            bg=COLORS["bg_tertiary"],
            fg=COLORS["fg"],
            insertbackground=COLORS["fg"],
            relief="flat",
            wrap="word",
            highlightthickness=1,
            highlightcolor=COLORS["border"],
            highlightbackground=COLORS["border"]
        )
        self.output_text.pack(fill="both", expand=True)

    def create_footer(self, parent):
        """Cria footer"""
        footer_frame = ttk.Frame(parent, style="Dark.TFrame")
        footer_frame.pack(fill="x", pady=(15, 0))

        self.stats_label = ttk.Label(
            footer_frame,
            text=self.get_stats(),
            style="Subtitle.TLabel"
        )
        self.stats_label.pack(side="left")

        version_label = ttk.Label(footer_frame, text="v1.0.0", style="Subtitle.TLabel")
        version_label.pack(side="right")

    def create_card(self, parent, expand=False):
        """Cria um card com fundo escuro"""
        card = tk.Frame(
            parent,
            bg=COLORS["bg_secondary"],
            highlightthickness=1,
            highlightbackground=COLORS["border"]
        )
        if expand:
            card.pack(fill="both", expand=True, pady=(0, 15))
        else:
            card.pack(fill="x", pady=(0, 15))

        inner = ttk.Frame(card, style="Card.TFrame")
        inner.pack(fill="both", expand=True, padx=15, pady=15)
        return inner

    def get_stats(self) -> str:
        """Retorna estatísticas"""
        try:
            files = list(TRANSCRIPTIONS_DIR.glob("**/*.txt"))
            return f"Total de transcrições: {len(files)}"
        except:
            return "Total de transcrições: 0"

    def paste_url(self):
        """Cola URL da área de transferência"""
        try:
            url = self.root.clipboard_get()
            self.url_entry.delete(0, "end")
            self.url_entry.insert(0, url)
        except:
            pass

    def copy_transcript(self):
        """Copia transcrição"""
        text = self.output_text.get("1.0", "end-1c")
        if text:
            self.root.clipboard_clear()
            self.root.clipboard_append(text)
            self.update_status("Transcrição copiada!")

    def open_folder(self):
        """Abre pasta de transcrições"""
        os.system(f'open "{TRANSCRIPTIONS_DIR}"')

    def update_status(self, message: str, progress: int = None):
        """Atualiza status"""
        self.status_var.set(message)
        if progress is not None:
            self.progress["value"] = progress
        self.root.update_idletasks()

    def append_output(self, text: str):
        """Adiciona texto ao output"""
        self.output_text.insert("end", text)
        self.output_text.see("end")
        self.root.update_idletasks()

    def start_transcription(self):
        """Inicia transcrição"""
        url = self.url_entry.get().strip()

        if not url:
            messagebox.showwarning("Aviso", "Por favor, insira uma URL de vídeo")
            return

        if self.is_transcribing:
            return

        self.output_text.delete("1.0", "end")
        self.is_transcribing = True
        self.transcribe_btn.configure(state="disabled", text="Transcrevendo...")

        thread = threading.Thread(target=self.transcribe_video, args=(url,))
        thread.daemon = True
        thread.start()

    def transcribe_video(self, url: str):
        """Processo de transcrição"""
        try:
            from pytubefix import YouTube
            import whisper
            import tempfile

            # 1. Conectar
            self.root.after(0, lambda: self.update_status("Conectando ao YouTube...", 10))

            yt = YouTube(url)
            duration_str = f"{yt.length // 60}:{yt.length % 60:02d}"

            self.root.after(0, lambda: self.update_status(f"Baixando: {yt.title[:40]}...", 20))
            self.root.after(0, lambda: self.append_output(f"Título: {yt.title}\n"))
            self.root.after(0, lambda: self.append_output(f"Canal: {yt.author}\n"))
            self.root.after(0, lambda: self.append_output(f"Duração: {duration_str}\n"))
            self.root.after(0, lambda: self.append_output("-" * 50 + "\n\n"))

            # 2. Baixar
            audio_stream = yt.streams.filter(only_audio=True).order_by('abr').desc().first()

            with tempfile.TemporaryDirectory() as temp_dir:
                audio_path = audio_stream.download(output_path=temp_dir, filename="audio.mp4")

                self.root.after(0, lambda: self.update_status("Carregando modelo Whisper...", 40))

                # 3. Carregar modelo
                model_name = self.model_var.get()
                model = whisper.load_model(model_name)

                self.root.after(0, lambda: self.update_status(f"Transcrevendo com {model_name}...", 50))

                # 4. Transcrever
                lang = self.lang_var.get()
                options = {} if lang == "auto" else {"language": lang}
                result = model.transcribe(audio_path, **options)

                self.root.after(0, lambda: self.update_status("Processando...", 90))

                # 5. Exibir resultado
                detected_lang = result.get("language", "unknown")
                self.root.after(0, lambda: self.append_output(f"Idioma: {detected_lang}\n\n"))
                self.root.after(0, lambda: self.append_output("TRANSCRIÇÃO:\n"))
                self.root.after(0, lambda: self.append_output("=" * 50 + "\n\n"))
                self.root.after(0, lambda: self.append_output(result["text"].strip() + "\n"))

                # 6. Salvar
                self.save_transcription(yt, result, url)

                self.root.after(0, lambda: self.update_status("Concluído!", 100))
                self.root.after(0, lambda: self.stats_label.configure(text=self.get_stats()))

        except Exception as e:
            self.root.after(0, lambda: self.update_status(f"Erro: {str(e)}", 0))
            self.root.after(0, lambda: self.append_output(f"\n\nERRO: {str(e)}\n"))

        finally:
            self.is_transcribing = False
            self.root.after(0, lambda: self.transcribe_btn.configure(state="normal", text="Transcrever"))

    def save_transcription(self, yt, result: dict, url: str):
        """Salva transcrição"""
        today = datetime.now()
        date_folder = TRANSCRIPTIONS_DIR / today.strftime("%Y-%m-%d")
        date_folder.mkdir(exist_ok=True)

        # Nome do arquivo
        title = re.sub(r'[<>:"/\\|?*]', '', yt.title)[:80]
        timestamp = today.strftime("%H%M%S")
        filepath = date_folder / f"{title}_{timestamp}.txt"

        # Conteúdo
        content = f"""{'=' * 70}
VIDEO TRANSCRIPTION
{'=' * 70}

Título: {yt.title}
Canal: {yt.author}
Duração: {yt.length // 60}:{yt.length % 60:02d}
URL: {url}
Data: {today.strftime("%Y-%m-%d %H:%M:%S")}
Modelo: {self.model_var.get()}
Idioma: {result.get('language', 'unknown')}

{'=' * 70}
TRANSCRIÇÃO:
{'=' * 70}

{result['text'].strip()}

{'=' * 70}
TIMESTAMPS:
{'=' * 70}

"""
        for seg in result.get("segments", []):
            start = f"{int(seg['start']//60):02d}:{int(seg['start']%60):02d}"
            end = f"{int(seg['end']//60):02d}:{int(seg['end']%60):02d}"
            content += f"[{start} -> {end}] {seg['text'].strip()}\n"

        with open(filepath, "w", encoding="utf-8") as f:
            f.write(content)

        # JSON
        json_data = {
            "video": {"title": yt.title, "author": yt.author, "duration": yt.length, "url": url},
            "transcription": {
                "date": today.isoformat(),
                "model": self.model_var.get(),
                "language": result.get("language"),
                "text": result["text"].strip(),
                "segments": result.get("segments", [])
            }
        }
        with open(filepath.with_suffix(".json"), "w", encoding="utf-8") as f:
            json.dump(json_data, f, ensure_ascii=False, indent=2)

        self.root.after(0, lambda: self.append_output(f"\n\nSalvo em: {filepath}\n"))


def main():
    root = tk.Tk()
    app = VideoTranscriberApp(root)
    root.mainloop()


if __name__ == "__main__":
    main()
