import os
import threading
import time
import tkinter as tk
import tkinter.filedialog
from tkinter import ttk

from PIL import Image, ImageOps, ImageTk

import icon
import lumen_profiler


class GuiApp:
    def __init__(self):
        self.tkroot = tk.Tk()
        self.lp = lumen_profiler.LumenProfiler()
        self.is_open = False
        self.is_analyzed = False
        self.uifont_l = ("MS UI Gothic", 14)
        self.uifont_s = ("MS UI Gothic", 11)

    def make_window(self):
        self.tkroot.title("Lumen Profiler")
        self.tkroot.geometry("800x600")

        # ファイル入力フレーム
        self.top_frame = tk.Frame(self.tkroot)
        self.top_frame.pack(fill=tk.X, pady=5)
        self.file_button = tk.Button(
            self.top_frame,
            text="映像ファイルを開く",
            command=self.open_movie,
            font=self.uifont_l,
        )
        self.file_button.pack(side=tk.LEFT, padx=(10, 0))
        self.file_text = tk.Label(self.top_frame, text="no movie", font=self.uifont_s)
        self.file_text.pack(side=tk.LEFT, fill=tk.X, padx=(20, 0))

        # 分析フレーム
        self.analize_frame = tk.Frame(self.tkroot)
        # self.analize_frame.pack(fill=tk.X, pady=5)
        self.analyze_button = tk.Button(
            self.analize_frame,
            text="分析実行",
            command=self.analyze,
            font=self.uifont_l,
        )
        self.analyze_button.pack(side=tk.LEFT, padx=(10, 0))
        self.interval_label = tk.Label(
            self.analize_frame,
            text="分析フレーム間隔",
            font=self.uifont_s,
        )
        self.interval_label.pack(side=tk.LEFT, padx=(20, 0))
        self.interval_text = tk.Entry(
            self.analize_frame, width=5, justify=tk.RIGHT, font=self.uifont_s
        )
        self.interval_text.insert(tk.END, "2")
        self.interval_text.pack(side=tk.LEFT)
        self.area_ratio_label = tk.Label(
            self.analize_frame, text="暗部の面積比率(%)", font=self.uifont_s
        )
        self.area_ratio_label.pack(side=tk.LEFT, padx=(20, 0))
        self.area_ratio_text = tk.Entry(
            self.analize_frame, width=5, justify=tk.RIGHT, font=self.uifont_s
        )
        self.area_ratio_text.insert(tk.END, "8.0")
        self.area_ratio_text.pack(side=tk.LEFT)
        self.sigma_label = tk.Label(
            self.analize_frame, text="輪郭の円滑性", font=self.uifont_s
        )
        self.sigma_label.pack(side=tk.LEFT, padx=(20, 0))
        self.sigma_text = tk.Entry(
            self.analize_frame, width=5, justify=tk.RIGHT, font=self.uifont_s
        )
        self.sigma_text.insert(tk.END, "5.0")
        self.sigma_text.pack(side=tk.LEFT)
        self.save_button = tk.Button(
            self.analize_frame,
            text="結果保存",
            command=self.on_save,
            font=self.uifont_l,
        )
        self.save_button.pack(side=tk.LEFT, padx=(20, 0))

        # 画像表示
        self.canvas = tk.Canvas(self.tkroot, bg="black")
        self.canvas.pack(fill=tk.BOTH, expand=True)
        self.time_slider = tk.Scale(
            self.tkroot,
            from_=0,
            to=0,
            orient=tk.HORIZONTAL,
            command=self.on_time_slider_change,
            font=self.uifont_s,
        )
        self.time_slider.pack(fill=tk.X, padx=(10, 10))

        # ステータスバー表示
        self.status_frame = tk.Frame(self.tkroot)
        self.status_frame.pack(fill=tk.X)
        self.status_text = tk.Text(
            self.status_frame,
            state="disabled",
            height=1,
            width=50,
            bg="lightgray",
            font=self.uifont_l,
        )
        self.status_text.pack(side=tk.LEFT, padx=(10, 0))
        self.progressbar = ttk.Progressbar(
            self.status_frame,
            orient="horizontal",
            length=200,
            mode="determinate",
            maximum=99,
        )
        self.progressbar.pack(side=tk.RIGHT, padx=(20, 10))
        self.update_status("映像ファイルを開いてください")

        self.tkroot.iconphoto(False, tk.PhotoImage(data=icon.icongif))
        self.tkroot.mainloop()

    # 分析
    def analyze(self):
        interval = int(self.interval_text.get())
        ratio = float(self.area_ratio_text.get()) / 100
        sigma = float(self.sigma_text.get())

        # 分析(ワーカースレッド）
        self.threaded_task(self.lp.profiling, (ratio, sigma, interval))
        # thread = threading.Thread(
        #     target=self.lp.profiling, args=(ratio, sigma, interval)
        # )
        # thread.start()
        # while thread.is_alive():
        #     self.progressbar.configure(value=self.lp.progress_count % 100)
        #     self.progressbar.update()
        # time.sleep(0.01)
        # thread.join()
        # self.progressbar.configure(value=0)
        # self.lp.profiling(ratio, sigma, interval)

        self.time_slider.config(to=len(self.lp.results) - 1)
        self.time_slider.set(0)
        self.is_analyzed = True
        self.show_image()
        self.update_status("分析完了")

    # 映像ファイルを開く
    def open_movie(self):
        self.moviefilename = tk.filedialog.askopenfilename(filetypes=[("mp4", "*.mp4")])
        if self.moviefilename == "":  # cancel
            return

        # 映像読み込み(ワーカースレッド）
        self.threaded_task(self.lp.load_movie, (self.moviefilename,))

        # 読み込み後の処理
        self.file_text.config(text=self.moviefilename)
        self.time_slider.set(0)
        self.time_slider.config(to=self.lp.frame_count - 1)
        self.is_analyzed = False
        self.show_image()
        self.update_status("条件を設定して分析を実行してください")
        if not self.is_open:
            self.analize_frame.pack(fill=tk.X, pady=5, after=self.top_frame)
            self.is_open = True

    # スレッド処理
    def threaded_task(self, task_func, task_args):
        thread = threading.Thread(target=task_func, args=task_args)
        thread.start()
        self.update_status("処理中")
        while thread.is_alive():
            self.progressbar.configure(value=self.lp.progress_count % 100)
            self.tkroot.update_idletasks()
            time.sleep(0.01)
        thread.join()
        self.progressbar.configure(value=0)
        # self.status_text.delete(1.0, tk.END)

    def update_status(self, text):
        self.status_text.config(state="normal")
        self.status_text.delete("1.0", tk.END)
        self.status_text.insert(tk.END, text)
        self.status_text.config(state="disabled")
        self.status_text.update()

    # 分析結果を保存
    def on_save(self):
        fn = os.path.splitext(os.path.basename(self.moviefilename))[0]
        filename = tk.filedialog.asksaveasfilename(
            initialfile=fn + "_分析結果.csv", filetypes=[("csv", "*.csv")]
        )
        if filename == "":  # cancel
            return
        self.lp.csv_output(filename)

    # スライダー操作イベント
    def on_time_slider_change(self, event):
        self.show_image()

    # 画像表示
    def show_image(self):
        rid = self.time_slider.get()
        if not self.is_analyzed:
            img = self.lp.bgr2rgb(self.lp.frames[rid])
        else:
            img = self.lp.bgr2rgb(self.lp.draw(rid))
        pil = Image.fromarray(img)
        pil = ImageOps.pad(pil, (self.canvas.winfo_width(), self.canvas.winfo_height()))
        self.disp = ImageTk.PhotoImage(pil)
        # self.canvas.delete("all")
        self.canvas.create_image(0, 0, image=self.disp, anchor=tk.NW)
        self.save_button.config(state=tk.NORMAL if self.is_analyzed else tk.DISABLED)


# main
if __name__ == "__main__":
    app = GuiApp()
    app.make_window()
