import tkinter as tk
from tkinter import scrolledtext
import subprocess
import threading
import sys
import os
import queue
import time

class ConsoleApp:
    def __init__(self, root, args):
        self.root = root
        self.args = args
        self.proc = None
        self.output_queue = queue.Queue()
        
        # 获取系统当前编码，尽量保证原样输出
        self.encoding = sys.stdout.encoding or 'utf-8'

        # 记录最后一次收到输出的时间
        self.last_output_time = time.time()

        root.title("AI 交互终端")
        root.geometry("900x600")

        # GUI 布局
        # 输出区域
        self.text_area = scrolledtext.ScrolledText(root, wrap=tk.WORD, font=("Consolas", 10))
        self.text_area.pack(expand=True, fill='both', padx=5, pady=5)

        # 输入区域
        input_frame = tk.Frame(root)
        input_frame.pack(fill='x', padx=5, pady=5)

        self.entry = tk.Entry(input_frame, font=("Consolas", 10))
        self.entry.pack(side=tk.LEFT, expand=True, fill='x')
        self.entry.bind('<Return>', self.send_input)

        # 说话模式复选框
        self.speak_mode = tk.BooleanVar(value=False)
        self.speak_check = tk.Checkbutton(input_frame, text="提示AI(说话)", variable=self.speak_mode, font=("Consolas", 9))
        self.speak_check.pack(side=tk.RIGHT, padx=5)

        self.kill_btn = tk.Button(input_frame, text="强制终止进程", command=self.force_terminate, bg="red", fg="white")
        self.kill_btn.pack(side=tk.RIGHT, padx=5)

        # 状态栏 (用于显示无输出时长)
        status_frame = tk.Frame(root)
        status_frame.pack(fill='x', padx=5, pady=(0, 5))
        self.time_label = tk.Label(status_frame, text="无输出时长: 00:00", font=("Consolas", 10), fg="gray")
        self.time_label.pack(side=tk.RIGHT)

        # 启动子进程 (合并 stderr 到 stdout)
        try:
            self.proc = subprocess.Popen(
                self.args,
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=subprocess.STDOUT,
                bufsize=0  # 无缓冲，确保实时性
            )
        except Exception as e:
            print(f"启动进程失败: {e}")
            sys.exit(1)

        # 启动读取子进程输出的线程
        self.output_thread = threading.Thread(target=self.read_output, daemon=True)
        self.output_thread.start()

        # 启动读取当前脚本控制台输入的线程 (允许直接在终端输入)
        self.stdin_thread = threading.Thread(target=self.read_stdin, daemon=True)
        self.stdin_thread.start()

        # 窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)

        # 开始轮询队列更新GUI
        self.update_gui()

    def read_output(self):
        """后台线程：实时读取子进程的输出"""
        fd = self.proc.stdout.fileno()
        while True:
            try:
                byte_data = os.read(fd, 1024)
                if not byte_data:
                    break # 进程结束
                
                # 只要收到数据，就更新最后输出时间
                self.last_output_time = time.time()

                # 1. 实时输出到当前脚本的 stdout (不加任何前缀)
                sys.stdout.buffer.write(byte_data)
                sys.stdout.buffer.flush()

                # 2. 放入队列供 GUI 使用
                try:
                    text = byte_data.decode(self.encoding, errors='replace')
                except:
                    text = byte_data.decode('utf-8', errors='replace')
                self.output_queue.put(text)
            except OSError:
                break # 管道已关闭

    def read_stdin(self):
        """后台线程：实时读取宿主控制台的 stdin 并转发给子进程"""
        while True:
            line = sys.stdin.readline()
            if not line:
                break
            try:
                self.proc.stdin.write(line.encode(self.encoding, errors='replace'))
                self.proc.stdin.flush()
            except:
                break

    def send_input(self, event):
        """GUI 输入框回车事件"""
        text = self.entry.get()
        self.entry.delete(0, tk.END)
        if not text:
            return

        # 如果勾选了"提示AI"，则直接输出到当前脚本的 stdout，不发给子进程
        if self.speak_mode.get():
            speak_text = text + '\n'
            # 输出到当前脚本控制台，供 AI 捕获
            sys.stdout.buffer.write(speak_text.encode(self.encoding, errors='replace'))
            sys.stdout.buffer.flush()
            
            # 在 GUI 中回显，让用户知道说了什么（使用不同颜色区分）
            self.text_area.insert(tk.END, speak_text, 'speak_tag')
            self.text_area.tag_config('speak_tag', foreground="blue")
            self.text_area.see(tk.END)
        else:
            # 正常模式：发给子进程
            text += '\n'
            try:
                self.proc.stdin.write(text.encode(self.encoding, errors='replace'))
                self.proc.stdin.flush()
            except Exception as e:
                self.output_queue.put(f"\n[输入发送失败: {e}]\n")

    def force_terminate(self):
        """强制终止子进程"""
        if self.proc and self.proc.poll() is None:
            print("用户终止了应用程序") # 输出到控制台 stdout
            self.output_queue.put("\n[用户终止了应用程序]\n")
            self.proc.kill()

    def on_closing(self):
        """关闭窗口时终止子进程"""
        if self.proc and self.proc.poll() is None:
            self.proc.kill()
        self.root.destroy()

    def update_gui(self):
        """主线程：从队列获取数据并更新GUI"""
        try:
            while True:
                text = self.output_queue.get_nowait()
                self.text_area.insert(tk.END, text)
                self.text_area.see(tk.END)
        except queue.Empty:
            pass

        # 计算并更新无输出时长
        if self.proc and self.proc.poll() is None:
            idle_seconds = int(time.time() - self.last_output_time)
            mins = idle_seconds // 60
            secs = idle_seconds % 60
            self.time_label.config(text=f"无输出时长: {mins:02d}:{secs:02d}")
        else:
            self.time_label.config(text="进程已结束")

        # 检查进程是否已结束
        if self.proc and self.proc.poll() is not None:
            if self.output_queue.empty():
                self.kill_btn.config(state=tk.DISABLED, bg="grey", text="进程已结束")
                # 进程结束且输出已读取完毕，自动关闭程序
                self.root.destroy()
                return # 停止轮询

        # 每 200ms 轮询一次 (减少CPU占用，时间显示不需要50ms那么频繁)
        self.root.after(200, self.update_gui)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("用法: python ai_console.py <command> [args...]")
        print("示例: python ai_console.py cmd")
        sys.exit(1)

    root = tk.Tk()
    app = ConsoleApp(root, sys.argv[1:])
    root.mainloop()