import platform
import textwrap
from tkinter import (
    Frame,
    Label,
    Button,
    StringVar,
    N,
    E,
    S,
    W,
    LEFT,
    DISABLED,
    NORMAL,
)

from numpy import where
import pandas as pd
import requests
from PIL import ImageTk, Image

from utils.consts import Consts


class ImgFrame(Frame):
    def __init__(self, master):
        super().__init__()
        self["height"] = 300
        self["width"] = 600
        self["bg"] = "white"


class SqrFrame(Frame):
    def __init__(self, master):
        super().__init__()
        self["height"] = 300
        self["width"] = 300
        # self["bg"] = "silver"


class RectFrame(Frame):
    def __init__(self, master):
        super().__init__()
        self["height"] = 300
        self["width"] = 1000
        # self["bg"] = "white"


class Patente:
    def __init__(self, master, df):
        self.master = master
        master.title("Patente")
        master.geometry("1200x560+0+0")
        self.current_index = 0
        self.counter = 1800
        self.button_label = StringVar()
        self.button_label.set(self.counter)
        self.info_var = StringVar()
        self.info_var.set("")
        self.q_txt = ""
        self.remained = 40
        self.answers = [""] * 40
        self.image_list = []
        self.df = df
        self.image_list = self.create_image_list()
        if platform.system() == "Darwin":
            self.START_PADY, self.FINISH_PADY = [11, 11]
        elif platform.system() == "Windows":
            self.START_PADY, self.FINISH_PADY = [14, 15]

        # Image
        self.image_frame = ImgFrame(master)
        self.image_frame.grid(row=0, column=0, sticky=W)
        self.my_img = ImageTk.PhotoImage(Image.open("temp.png"))
        self.img_holder = Label(self.image_frame, image=self.my_img).grid(
            row=0, column=0, sticky=W
        )

        # Question
        self.question_frame = RectFrame(master)
        self.question_box = Label(
            self.question_frame, text=self.q_txt, justify=LEFT, font="Courier 18"
        )
        self.question_frame.grid(row=0, column=1, sticky=W + N)
        self.question_box.grid(sticky=W + N)
        # Timer
        self.timer_frame = SqrFrame(master)
        self.timer_frame.grid(row=0, column=2, sticky=N + E)
        self.timer_box = Label(
            self.timer_frame, textvariable=self.button_label, font="Courier 40"
        )

        # Buttons
        self.start_finish_frame = SqrFrame(master)
        self.start_finish_frame.grid(row=1, column=0, sticky=W + N)

        self.exam_flow_frame = RectFrame(master)
        self.exam_flow_frame.grid(row=1, column=1, sticky=W + N)

        self.status_frame = SqrFrame(master)
        self.status_frame.grid(row=1, column=2, sticky=N)

        self.start_button = Button(
            self.start_finish_frame,
            padx=52,
            pady=self.START_PADY,
            text="START ",
            fg="blue",
            font="Courier 60",
            command=self.start_test,
        )
        self.start_button.grid(row=0, column=0)

        self.finish_button = Button(
            self.start_finish_frame,
            padx=52,
            pady=self.FINISH_PADY,
            text="FINISH",
            fg="red",
            font="Courier 60",
            command=self.finish_test,
        )
        self.finish_button.grid(row=1, column=0)

        self.previous_button = Button(
            self.exam_flow_frame,
            state=DISABLED,
            padx=6,
            width=4,
            height=3,
            text="<",
            fg="gray",
            font="Courier 55",
            command=self.previous_question,
        )
        self.previous_button.pack(side=LEFT)

        self.f_button = Button(
            self.exam_flow_frame,
            state=DISABLED,
            padx=5,
            width=4,
            height=3,
            text="F",
            fg="red",
            font="Courier 55",
            command=lambda: self.update_answer("F"),
        )
        self.f_button.pack(side=LEFT)

        self.v_button = Button(
            self.exam_flow_frame,
            state=DISABLED,
            padx=5,
            width=4,
            height=3,
            text="V",
            fg="green",
            font="Courier 55",
            command=lambda: self.update_answer("V"),
        )
        self.v_button.pack(side=LEFT)

        self.next_button = Button(
            self.exam_flow_frame,
            state=DISABLED,
            padx=6,
            width=4,
            height=3,
            text=">",
            fg="gray",
            font="Courier 55",
            command=self.next_question,
        )
        self.next_button.pack(side=LEFT)

        self.btn_list = [
            self.previous_button,
            self.f_button,
            self.v_button,
            self.next_button,
            self.start_button,
            self.finish_button,
        ]

        # Stats
        self.info_box = Label(
            self.status_frame,
            textvariable=self.info_var,
            justify=LEFT,
            font="Courier 30",
        )
        self.info_box.grid(sticky=E + S)

        # Answers
        self.answer_frame = Frame(master)
        self.answer_frame.grid(row=2, column=1, sticky=N)

        self.selected_answer = {}
        r = 3
        c = 0
        for i in range(0, 40):
            self.selected_answer[str(i)] = Label(
                self.answer_frame,
                text=f"{i+1}",
                width=2,
                height=1,
                fg="blue",
                anchor=N,
                font="Courier 16",
            )
            self.selected_answer[str(i)].grid(row=r, column=c)
            c += 1
            if i > 0:
                if (i + 1) % 20 == 0:
                    r += 1
                    c = 0

    def download_question_img(self, img_name, img_path):
        with open(img_name, "wb") as file:
            file.write(requests.get(f"{Consts.BASE_URL}{img_path}").content)

    def gui_question_img(self, img_name):
        with Image.open(img_name) as temp_image:
            temp_image.resize((300, 292), Image.LANCZOS).save(img_name)
            return ImageTk.PhotoImage(Image.open(img_name))

    def create_image_list(self):
        for idx, img_path in enumerate(self.df["Figura"].values):
            if img_path:
                try:
                    current_img = f"{idx}.png"
                    self.download_question_img(current_img, img_path)
                    self.image_list.append(self.gui_question_img(current_img))
                except Exception as e:
                    print(e)
            else:
                self.image_list.append(None)
        return self.image_list

    def image_var(self):
        if self.df.iloc[self.current_index, 0]:
            return self.image_list[self.current_index]
        else:
            return ImageTk.PhotoImage(Image.open("temp.png"))

    def question_wraper(self, question, width):
        return "\n".join(textwrap.wrap(question.strip(), width=width))

    def exam_correct_answers(self, df_obj):
        return "".join(
            (
                f"{idx + 1:02d}.{df_obj.iloc[idx, 2]}  "
                for idx, _ in enumerate([""] * 40)
            )
        )

    def show_correct_answer(self, true_answers):
        return f"Correct answers:\n\n{self.question_wraper(true_answers, 30)}"

    def examinee_current_result(self, total_correct):
        res = "PASS" if total_correct >= 36 else "FAIL"
        return f"{res} with {40 - total_correct} False answers\n\n"

    def display(self, df_obj, frame):
        answer_df = pd.DataFrame({"answers": self.answers})
        frame.destroy()
        correct_sum = sum(
            where(df_obj.Risposta == answer_df.answers, "True", "False") == "True"
        )
        correct_answers = self.exam_correct_answers(df_obj)
        result = self.examinee_current_result(correct_sum)
        self.question_box.config(
            text=f"{result}{self.show_correct_answer(correct_answers)}"
        )
        return result.split()[0]

    def info_set(self, remained_num, var_str):
        var_str.set(
            f"Answered: {abs(remained_num - 40):2d}\nRemained: {remained_num:2d}\n"
        )

    def change_button_state(self, button_objs, state):
        for btn in button_objs:
            btn["state"] = state

    def update_question(self, q_box, curr_idx, df_obj, w=50):
        q_box.config(
            text=self.question_wraper(
                f"{curr_idx + 1}.{df_obj.loc[curr_idx]['Domanda']}", w
            )
        )

    def update_image(self, img_fr, im_var):
        try:
            Label(img_fr).grid_forget()
            Label(img_fr, image=im_var).grid(row=0, column=0)
        except:
            pass

    def show_correct_answer(self, true_answers):
        return f"Correct answers:\n\n{self.question_wraper(true_answers, 30)}"

    def examinee_current_result(self, total_correct):
        res = "PASS" if total_correct >= 36 else "FAIL"
        return f"{res} with {40 - total_correct} False answers\n\n"

    def timer_func(self, stop, label):
        if stop > 0:
            m, s = divmod(stop, 60)
            time_left = f"{m:02d}:{s:02d}\r"
            stop -= 1
            label.set(time_left)
            if stop <= 58:
                self.timer_box["fg"] = "red"
            self.timer_frame.after(1000, lambda: self.timer_func(stop, label))
        else:
            res = self.display(self.df, self.timer_frame)
            self.my_img = ImageTk.PhotoImage(Image.open(f"{res}.png"))
            self.update_image(self.image_frame, self.my_img)
            self.change_button_state(self.btn_list, DISABLED)

    def start_test(self):
        self.update_question(self.question_box, self.current_index, self.df)
        self.update_image(self.image_frame, self.image_var())
        self.info_set(40, self.info_var)
        self.timer_box.grid(row=0, column=1, sticky=N + E)
        self.timer_func(self.counter, self.button_label)
        self.start_button["state"] = DISABLED
        self.change_button_state(self.btn_list[:-2], NORMAL)

    def finish_test(self):
        self.timer_func(0, self.button_label)

    def dissable_button(self):
        if self.current_index == 0:
            self.previous_button["state"] = DISABLED
        elif self.current_index == 39:
            self.next_button["state"] = DISABLED
        else:
            self.change_button_state([self.previous_button, self.next_button], NORMAL)

    def next_question(self):
        if self.current_index < 39:
            self.current_index += 1
            self.update_question(self.question_box, self.current_index, self.df)
            self.update_image(self.image_frame, self.image_var())
            self.dissable_button()

    def previous_question(self):
        if self.current_index > 0:
            self.current_index -= 1
            if self.current_index > -1:
                self.update_question(self.question_box, self.current_index, self.df)
                self.update_image(self.image_frame, self.image_var())
                self.dissable_button()

    def change_qlink_color(self, selected):
        self.selected_answer[str(self.current_index)]["fg"] = {
            "F": "red",
            "V": "green",
        }[selected]

    def update_answer(self, selected):
        self.answers[self.current_index] = selected
        self.change_qlink_color(selected)
        remaining = self.answers.count("")
        self.info_set(remaining, self.info_var)
        self.next_question()

import platform
import textwrap
from tkinter import (
    Frame,
    Label,
    Button,
    StringVar,
    N,
    E,
    S,
    W,
    LEFT,
    DISABLED,
    NORMAL,
)

from numpy import where
import pandas as pd
import requests
from PIL import ImageTk, Image

from utils.consts import Consts


class ImgFrame(Frame):
    def __init__(self, master):
        super().__init__()
        self["height"] = 300
        self["width"] = 600
        self["bg"] = "white"


class SqrFrame(Frame):
    def __init__(self, master):
        super().__init__()
        self["height"] = 300
        self["width"] = 300
        # self["bg"] = "silver"


class RectFrame(Frame):
    def __init__(self, master):
        super().__init__()
        self["height"] = 300
        self["width"] = 1000
        # self["bg"] = "white"


class Patente:
    def __init__(self, master, df):
        self.master = master
        master.title("Patente")
        master.geometry("1200x560+0+0")
        self.current_index = 0
        self.counter = 1800
        self.button_label = StringVar()
        self.button_label.set(self.counter)
        self.info_var = StringVar()
        self.info_var.set("")
        self.q_txt = ""
        self.remained = 40
        self.answers = [""] * 40
        self.image_list = []
        self.df = df
        self.image_list = self.create_image_list()
        if platform.system() == "Darwin":
            self.START_PADY, self.FINISH_PADY = [11, 11]
        elif platform.system() == "Windows":
            self.START_PADY, self.FINISH_PADY = [14, 15]

        # Image
        self.image_frame = ImgFrame(master)
        self.image_frame.grid(row=0, column=0, sticky=W)
        self.my_img = ImageTk.PhotoImage(Image.open("temp.png"))
        self.img_holder = Label(self.image_frame, image=self.my_img).grid(
            row=0, column=0, sticky=W
        )

        # Question
        self.question_frame = RectFrame(master)
        self.question_box = Label(
            self.question_frame, text=self.q_txt, justify=LEFT, font="Courier 18"
        )
        self.question_frame.grid(row=0, column=1, sticky=W + N)
        self.question_box.grid(sticky=W + N)
        # Timer
        self.timer_frame = SqrFrame(master)
        self.timer_frame.grid(row=0, column=2, sticky=N + E)
        self.timer_box = Label(
            self.timer_frame, textvariable=self.button_label, font="Courier 40"
        )

        # Buttons
        self.start_finish_frame = SqrFrame(master)
        self.start_finish_frame.grid(row=1, column=0, sticky=W + N)

        self.exam_flow_frame = RectFrame(master)
        self.exam_flow_frame.grid(row=1, column=1, sticky=W + N)

        self.status_frame = SqrFrame(master)
        self.status_frame.grid(row=1, column=2, sticky=N)

        self.start_button = Button(
            self.start_finish_frame,
            padx=52,
            pady=self.START_PADY,
            text="START ",
            fg="blue",
            font="Courier 60",
            command=self.start_test,
        )
        self.start_button.grid(row=0, column=0)

        self.finish_button = Button(
            self.start_finish_frame,
            padx=52,
            pady=self.FINISH_PADY,
            text="FINISH",
            fg="red",
            font="Courier 60",
            command=self.finish_test,
        )
        self.finish_button.grid(row=1, column=0)

        self.previous_button = Button(
            self.exam_flow_frame,
            state=DISABLED,
            padx=6,
            width=4,
            height=3,
            text="<",
            fg="gray",
            font="Courier 55",
            command=self.previous_question,
        )
        self.previous_button.pack(side=LEFT)

        self.f_button = Button(
            self.exam_flow_frame,
            state=DISABLED,
            padx=5,
            width=4,
            height=3,
            text="F",
            fg="red",
            font="Courier 55",
            command=lambda: self.update_answer("F"),
        )
        self.f_button.pack(side=LEFT)

        self.v_button = Button(
            self.exam_flow_frame,
            state=DISABLED,
            padx=5,
            width=4,
            height=3,
            text="V",
            fg="green",
            font="Courier 55",
            command=lambda: self.update_answer("V"),
        )
        self.v_button.pack(side=LEFT)

        self.next_button = Button(
            self.exam_flow_frame,
            state=DISABLED,
            padx=6,
            width=4,
            height=3,
            text=">",
            fg="gray",
            font="Courier 55",
            command=self.next_question,
        )
        self.next_button.pack(side=LEFT)

        self.btn_list = [
            self.previous_button,
            self.f_button,
            self.v_button,
            self.next_button,
            self.start_button,
            self.finish_button,
        ]

        # Stats
        self.info_box = Label(
            self.status_frame,
            textvariable=self.info_var,
            justify=LEFT,
            font="Courier 30",
        )
        self.info_box.grid(sticky=E + S)

        # Answers
        self.answer_frame = Frame(master)
        self.answer_frame.grid(row=2, column=1, sticky=N)

        self.selected_answer = {}
        r = 3
        c = 0
        for i in range(0, 40):
            self.selected_answer[str(i)] = Label(
                self.answer_frame,
                text=f"{i+1}",
                width=2,
                height=1,
                fg="blue",
                anchor=N,
                font="Courier 16",
            )
            self.selected_answer[str(i)].grid(row=r, column=c)
            c += 1
            if i > 0:
                if (i + 1) % 20 == 0:
                    r += 1
                    c = 0

    def download_question_img(self, img_name, img_path):
        with open(img_name, "wb") as file:
            file.write(requests.get(f"{Consts.BASE_URL}{img_path}").content)

    def gui_question_img(self, img_name):
        with Image.open(img_name) as temp_image:
            temp_image.resize((300, 292), Image.LANCZOS).save(img_name)
            return ImageTk.PhotoImage(Image.open(img_name))

    def create_image_list(self):
        for idx, img_path in enumerate(self.df["Figura"].values):
            if img_path:
                try:
                    current_img = f"{idx}.png"
                    self.download_question_img(current_img, img_path)
                    self.image_list.append(self.gui_question_img(current_img))
                except Exception as e:
                    print(e)
            else:
                self.image_list.append(None)
        return self.image_list

    def image_var(self):
        if self.df.iloc[self.current_index, 0]:
            return self.image_list[self.current_index]
        else:
            return ImageTk.PhotoImage(Image.open("temp.png"))

    def question_wraper(self, question, width):
        return "\n".join(textwrap.wrap(question.strip(), width=width))

    def exam_correct_answers(self, df_obj):
        return "".join(
            (
                f"{idx + 1:02d}.{df_obj.iloc[idx, 2]}  "
                for idx, _ in enumerate([""] * 40)
            )
        )

    def show_correct_answer(self, true_answers):
        return f"Correct answers:\n\n{self.question_wraper(true_answers, 30)}"

    def examinee_current_result(self, total_correct):
        res = "PASS" if total_correct >= 36 else "FAIL"
        return f"{res} with {40 - total_correct} False answers\n\n"

    def display(self, df_obj, frame):
        answer_df = pd.DataFrame({"answers": self.answers})
        frame.destroy()
        correct_sum = sum(
            where(df_obj.Risposta == answer_df.answers, "True", "False") == "True"
        )
        correct_answers = self.exam_correct_answers(df_obj)
        result = self.examinee_current_result(correct_sum)
        self.question_box.config(
            text=f"{result}{self.show_correct_answer(correct_answers)}"
        )
        return result.split()[0]

    def info_set(self, remained_num, var_str):
        var_str.set(
            f"Answered: {abs(remained_num - 40):2d}\nRemained: {remained_num:2d}\n"
        )

    def change_button_state(self, button_objs, state):
        for btn in button_objs:
            btn["state"] = state

    def update_question(self, q_box, curr_idx, df_obj, w=50):
        q_box.config(
            text=self.question_wraper(
                f"{curr_idx + 1}.{df_obj.loc[curr_idx]['Domanda']}", w
            )
        )

    def update_image(self, img_fr, im_var):
        try:
            Label(img_fr).grid_forget()
            Label(img_fr, image=im_var).grid(row=0, column=0)
        except:
            pass

    def show_correct_answer(self, true_answers):
        return f"Correct answers:\n\n{self.question_wraper(true_answers, 30)}"

    def examinee_current_result(self, total_correct):
        res = "PASS" if total_correct >= 36 else "FAIL"
        return f"{res} with {40 - total_correct} False answers\n\n"

    def timer_func(self, stop, label):
        if stop > 0:
            m, s = divmod(stop, 60)
            time_left = f"{m:02d}:{s:02d}\r"
            stop -= 1
            label.set(time_left)
            if stop <= 58:
                self.timer_box["fg"] = "red"
            self.timer_frame.after(1000, lambda: self.timer_func(stop, label))
        else:
            res = self.display(self.df, self.timer_frame)
            self.my_img = ImageTk.PhotoImage(Image.open(f"{res}.png"))
            self.update_image(self.image_frame, self.my_img)
            self.change_button_state(self.btn_list, DISABLED)

    def start_test(self):
        self.update_question(self.question_box, self.current_index, self.df)
        self.update_image(self.image_frame, self.image_var())
        self.info_set(40, self.info_var)
        self.timer_box.grid(row=0, column=1, sticky=N + E)
        self.timer_func(self.counter, self.button_label)
        self.start_button["state"] = DISABLED
        self.change_button_state(self.btn_list[:-2], NORMAL)

    def finish_test(self):
        self.timer_func(0, self.button_label)

    def dissable_button(self):
        if self.current_index == 0:
            self.previous_button["state"] = DISABLED
        elif self.current_index == 39:
            self.next_button["state"] = DISABLED
        else:
            self.change_button_state([self.previous_button, self.next_button], NORMAL)

    def next_question(self):
        if self.current_index < 39:
            self.current_index += 1
            self.update_question(self.question_box, self.current_index, self.df)
            self.update_image(self.image_frame, self.image_var())
            self.dissable_button()

    def previous_question(self):
        if self.current_index > 0:
            self.current_index -= 1
            if self.current_index > -1:
                self.update_question(self.question_box, self.current_index, self.df)
                self.update_image(self.image_frame, self.image_var())
                self.dissable_button()

    def change_qlink_color(self, selected):
        self.selected_answer[str(self.current_index)]["fg"] = {
            "F": "red",
            "V": "green",
        }[selected]

    def update_answer(self, selected):
        self.answers[self.current_index] = selected
        self.change_qlink_color(selected)
        remaining = self.answers.count("")
        self.info_set(remaining, self.info_var)
        self.next_question()

# self["bg"] = "silver" # self["bg"] = "white" # Image # Question # Timer # Buttons # Stats # Answers