import tkinter as tk
from tkinter import Button, Listbox, Toplevel, Label, messagebox, Frame, Scrollbar
import subprocess
import cv2
from PIL import Image, ImageTk
import modules.util.const as const
import threading


class CameraSelector(Toplevel):
    def __init__(self, parent):
        super().__init__(parent)
        self.title("カメラの選択")
        self.geometry("800x400")
        self.cap = None
        self.stop_thread = True

        self.cameras = self.get_cameras()

        self.setup_gui()

        self.protocol("WM_DELETE_WINDOW", self.on_close)

    def setup_gui(self):
        """GUIのセットアップ"""
        self.setup_camera_frame()
        self.setup_control_frame()

    def setup_camera_frame(self):
        """カメラフレームのセットアップ"""
        self.camera_frame = Frame(self)
        self.camera_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.feed_label = Label(self.camera_frame)
        self.feed_label.pack(pady=20, padx=20, fill=tk.BOTH, expand=True)

    def setup_control_frame(self):
        """コントロールフレームのセットアップ"""
        self.control_frame = Frame(self)
        self.control_frame.pack(side=tk.RIGHT, fill=tk.BOTH, padx=10, pady=10)
        scrollbar = Scrollbar(self.control_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.listbox = Listbox(self.control_frame, yscrollcommand=scrollbar.set)
        for cam_id, name in self.cameras:
            self.listbox.insert(tk.END, f"[{cam_id}] {name}")
        self.listbox.pack(pady=20, padx=20, fill=tk.BOTH, expand=True)
        scrollbar.config(command=self.listbox.yview)
        self.listbox.bind("<Double-Button-1>", self.on_select_camera_id)

        self.preview_button = Button(self.control_frame, text="カメラ画像確認", command=self.on_preview_camera)
        self.preview_button.pack(pady=10)

        self.select_id_button = Button(self.control_frame, text="カメラID確定", command=self.finalize_selection)
        self.select_id_button.pack(pady=10)

    def get_cameras(self):
        """CameraFinder.exeを使用して利用可能なカメラのIDと名前を取得する"""
        result = subprocess.run([const.CAMERA_FINDER_PATH], capture_output=True, text=True)
        lines = result.stdout.splitlines()
        cameras = []
        for line in lines:
            if "[" in line and "]" in line:
                idx = line.index("[")
                id_end = line.index("]")
                cam_id = int(line[idx + 1 : id_end])
                cam_name = line[id_end + 2 :].strip()
                cameras.append((cam_id, cam_name))
        return cameras

    def on_select_camera_id(self, event=None):
        selected_idx = self.listbox.curselection()
        if not selected_idx:
            return
        self.selected_cam_id = self.cameras[selected_idx[0]][0]
        self.listbox.selection_set(selected_idx)

    def on_preview_camera(self):
        if not hasattr(self, "selected_cam_id"):
            messagebox.showinfo("情報", "カメラIDを選択してください。")
            return

        if self.cap and self.cap.isOpened():
            self.cap.release()

        self.stop_thread = False
        self.thread = threading.Thread(target=self.show_camera_feed, args=(self.selected_cam_id,))
        self.thread.start()

    def show_camera_feed(self, cam_id):
        self.cap = cv2.VideoCapture(cam_id)
        if not self.cap.isOpened():
            messagebox.showerror("エラー", "カメラを開けませんでした。")
            return

        while not self.stop_thread:
            ret, frame = self.cap.read()
            if ret:
                frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                # アスペクト比を保ったままリサイズ
                h, w, _ = frame.shape
                aspect_ratio = w / h
                new_width = int(self.feed_label.winfo_height() * aspect_ratio)
                frame = cv2.resize(frame, (new_width, self.feed_label.winfo_height()))
                image = Image.fromarray(frame)
                photo = ImageTk.PhotoImage(image=image)
                self.feed_label.config(image=photo)
                self.feed_label.image = photo

        self.cap.release()

    def get_selected_camera_id(self):
        """選択されたカメラIDを返す"""
        if hasattr(self, "selected_cam_id"):
            return self.selected_cam_id
        return None

    def finalize_selection(self):
        if not hasattr(self, "selected_cam_id"):
            messagebox.showinfo("情報", "カメラIDを選択してください。")
            return
        self.selected_camera_id = self.get_selected_camera_id()
        self.master.camera_id = self.selected_camera_id
        messagebox.showinfo("情報", f"カメラID {self.selected_camera_id} が確定されました。")
        self.destroy()

    def on_close(self):
        self.stop_thread = True  # スレッドを停止
        if hasattr(self, "thread"):
            self.thread.join()  # スレッドが終了するのを待つ
        if self.cap and self.cap.isOpened():
            self.cap.release()
        self.destroy()  # ウィンドウを終了

    @staticmethod
    def get_default_camera_id():
        """デフォルトで "VGA Camera" という名前のカメラIDを返す"""
        result = subprocess.run([const.CAMERA_FINDER_PATH], capture_output=True, text=True)
        lines = result.stdout.splitlines()
        for line in lines:
            if "VGA Camera" in line:
                idx = line.index("[")
                id_end = line.index("]")
                cam_id = int(line[idx + 1 : id_end])
                return cam_id
        return None
