import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import os
import threading
import sys
import ffmpeg

class AudioConverterApp:
    def __init__(self, master):
        self.master = master
        master.title("小智AI OGG音频批量转换工具")
        master.geometry("680x600")  # 调整窗口高度

        # 初始化变量
        self.mode = tk.StringVar(value="audio_to_ogg")
        self.output_dir = tk.StringVar()
        self.output_dir.set(os.path.abspath("output"))
        self.enable_loudnorm = tk.BooleanVar(value=True)
        self.target_lufs = tk.DoubleVar(value=-16.0)

        # 创建UI组件
        self.create_widgets()
        self.redirect_output()

    def create_widgets(self):
        # 模式选择
        mode_frame = ttk.LabelFrame(self.master, text="转换模式")
        mode_frame.grid(row=0, column=0, padx=10, pady=5, sticky="ew")
        
        ttk.Radiobutton(mode_frame, text="音频转到OGG", variable=self.mode,
                        value="audio_to_ogg", command=self.toggle_settings,
                        width=12).grid(row=0, column=0, padx=5)
        ttk.Radiobutton(mode_frame, text="OGG转回音频", variable=self.mode,
                        value="ogg_to_audio", command=self.toggle_settings,
                        width=12).grid(row=0, column=1, padx=5)

        # 响度设置
        self.loudnorm_frame = ttk.Frame(self.master)
        self.loudnorm_frame.grid(row=1, column=0, padx=10, pady=5, sticky="ew")
        
        ttk.Checkbutton(self.loudnorm_frame, text="启用响度调整", 
                       variable=self.enable_loudnorm, width=15
                       ).grid(row=0, column=0, padx=2)
        ttk.Entry(self.loudnorm_frame, textvariable=self.target_lufs, 
                 width=6).grid(row=0, column=1, padx=2)
        ttk.Label(self.loudnorm_frame, text="LUFS").grid(row=0, column=2, padx=2)

        # 文件选择
        file_frame = ttk.LabelFrame(self.master, text="输入文件")
        file_frame.grid(row=2, column=0, padx=10, pady=5, sticky="nsew")
        
        # 文件操作按钮
        ttk.Button(file_frame, text="选择文件", command=self.select_files,
                  width=12).grid(row=0, column=0, padx=5, pady=2)
        ttk.Button(file_frame, text="移除选中", command=self.remove_selected,
                  width=12).grid(row=0, column=1, padx=5, pady=2)
        ttk.Button(file_frame, text="清空列表", command=self.clear_files,
                  width=12).grid(row=0, column=2, padx=5, pady=2)

        # 文件列表（使用Treeview）
        self.tree = ttk.Treeview(file_frame, columns=("selected", "filename"), 
                               show="headings", height=8)
        self.tree.heading("selected", text="选中", anchor=tk.W)
        self.tree.heading("filename", text="文件名", anchor=tk.W)
        self.tree.column("selected", width=60, anchor=tk.W)
        self.tree.column("filename", width=600, anchor=tk.W)
        self.tree.grid(row=1, column=0, columnspan=3, sticky="nsew", padx=5, pady=2)
        self.tree.bind("<ButtonRelease-1>", self.on_tree_click)

        # 输出目录
        output_frame = ttk.LabelFrame(self.master, text="输出目录")
        output_frame.grid(row=3, column=0, padx=10, pady=5, sticky="ew")
        
        ttk.Entry(output_frame, textvariable=self.output_dir, width=60
                 ).grid(row=0, column=0, padx=5, sticky="ew")
        ttk.Button(output_frame, text="浏览", command=self.select_output_dir,
                  width=8).grid(row=0, column=1, padx=5)

        # 转换按钮区域
        button_frame = ttk.Frame(self.master)
        button_frame.grid(row=4, column=0, padx=10, pady=10, sticky="ew")
        
        ttk.Button(button_frame, text="转换全部文件", command=lambda: self.start_conversion(True),
                  width=15).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="转换选中文件", command=lambda: self.start_conversion(False),
                  width=15).pack(side=tk.LEFT, padx=5)

        # 日志区域
        log_frame = ttk.LabelFrame(self.master, text="日志")
        log_frame.grid(row=5, column=0, padx=10, pady=5, sticky="nsew")
        
        self.log_text = tk.Text(log_frame, height=14, width=80)
        self.log_text.pack(fill=tk.BOTH, expand=True)

        # 配置布局权重
        self.master.columnconfigure(0, weight=1)
        self.master.rowconfigure(2, weight=1)
        self.master.rowconfigure(5, weight=3)
        file_frame.columnconfigure(0, weight=1)
        file_frame.rowconfigure(1, weight=1)

    def toggle_settings(self):
        if self.mode.get() == "audio_to_ogg":
            self.loudnorm_frame.grid()
        else:
            self.loudnorm_frame.grid_remove()

    def select_files(self):
        file_types = [
            ("音频文件", "*.wav *.mogg *.ogg *.flac") if self.mode.get() == "audio_to_ogg" 
            else ("ogg文件", "*.ogg")
        ]
        
        files = filedialog.askopenfilenames(filetypes=file_types)
        for f in files:
            self.tree.insert("", tk.END, values=("[ ]", os.path.basename(f)), tags=(f,))

    def on_tree_click(self, event):
        """处理复选框点击事件"""
        region = self.tree.identify("region", event.x, event.y)
        if region == "cell":
            col = self.tree.identify_column(event.x)
            item = self.tree.identify_row(event.y)
            if col == "#1":  # 点击的是选中列
                current_val = self.tree.item(item, "values")[0]
                new_val = "[√]" if current_val == "[ ]" else "[ ]"
                self.tree.item(item, values=(new_val, self.tree.item(item, "values")[1]))

    def remove_selected(self):
        """移除选中的文件"""
        to_remove = []
        for item in self.tree.get_children():
            if self.tree.item(item, "values")[0] == "[√]":
                to_remove.append(item)
        for item in reversed(to_remove):
            self.tree.delete(item)

    def clear_files(self):
        """清空所有文件"""
        for item in self.tree.get_children():
            self.tree.delete(item)

    def select_output_dir(self):
        path = filedialog.askdirectory()
        if path:
            self.output_dir.set(path)

    def redirect_output(self):
        class StdoutRedirector:
            def __init__(self, text_widget):
                self.text_widget = text_widget
                self.original_stdout = sys.stdout

            def write(self, message):
                self.text_widget.insert(tk.END, message)
                self.text_widget.see(tk.END)
                self.original_stdout.write(message)

            def flush(self):
                self.original_stdout.flush()

        sys.stdout = StdoutRedirector(self.log_text)

    def start_conversion(self, convert_all):
        """开始转换"""
        input_files = []
        for item in self.tree.get_children():
            if convert_all or self.tree.item(item, "values")[0] == "[√]":
                input_files.append(self.tree.item(item, "tags")[0])
        
        if not input_files:
            msg = "没有找到可转换的文件" if convert_all else "没有选中任何文件"
            messagebox.showwarning("警告", msg)
            return
        
        os.makedirs(self.output_dir.get(), exist_ok=True)

        try:
            if self.mode.get() == "audio_to_ogg":
                target_lufs = self.target_lufs.get() if self.enable_loudnorm.get() else None
                thread = threading.Thread(target=self.convert_audio_to_ogg, args=(target_lufs, input_files))
            else:
                thread = threading.Thread(target=self.convert_ogg_to_audio, args=(input_files,))
            
            thread.start()
        except Exception as e:
            print(f"转换初始化失败: {str(e)}")

    def convert_audio_to_ogg(self, target_lufs, input_files):
        """音频转到ogg转换逻辑"""
        for input_path in input_files:
            try:
                filename = os.path.basename(input_path)
                base_name = os.path.splitext(filename)[0]
                output_path = os.path.join(self.output_dir.get(), f"{base_name}.ogg")
                
                print(f"正在转换: {filename}")
                (
                    ffmpeg
                    .input(input_path)
                    .output(output_path, acodec='libopus', audio_bitrate='16k', ac=1, ar=16000, frame_duration=60)
                    .run(overwrite_output=True)
                )
                print(f"转换成功: {filename}\n")
            except Exception as e:
                print(f"转换失败: {str(e)}\n")

    def convert_ogg_to_audio(self, input_files):
        """ogg转回音频转换逻辑"""
        for input_path in input_files:
            try:
                filename = os.path.basename(input_path)
                base_name = os.path.splitext(filename)[0]
                output_path = os.path.join(self.output_dir.get(), f"{base_name}.ogg")
                
                print(f"正在转换: {filename}")
                (
                    ffmpeg
                    .input(input_path)
                    .output(output_path, acodec='libopus', audio_bitrate='16k', ac=1, ar=16000, frame_duration=60)
                    .run(overwrite_output=True)
                )
                print(f"转换成功: {filename}\n")
            except Exception as e:
                print(f"转换失败: {str(e)}\n")

if __name__ == "__main__":
    root = tk.Tk()
    app = AudioConverterApp(root)
    root.mainloop()
