import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import time


class StopwatchApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Секундомер")
        self.geometry("560x480")
        self.minsize(400, 350)

        self.running = False
        self.accumulated = 0.0
        self.start_time = None
        self.after_id = None
        self.previous_lap_total = 0.0
        self.lap_count = 0
        self.lap_data = {}

        self.display_var = tk.StringVar(value="00:00.00")

        self._create_widgets()
        self._configure_tags()
        self._update_display()

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

    def _create_widgets(self):
        display_frame = tk.Frame(self)
        display_frame.pack(pady=20)

        self.display_label = tk.Label(
            display_frame,
            textvariable=self.display_var,
            font=("Consolas", 64, "bold"),
            bg="black",
            fg="white",
            anchor="center",
            padx=20,
            pady=10
        )
        self.display_label.pack()

        buttons_frame = tk.Frame(self)
        buttons_frame.pack(pady=10)

        self.start_stop_btn = ttk.Button(buttons_frame, text="Старт", command=self._on_start_stop)
        self.start_stop_btn.pack(side=tk.LEFT, padx=5)

        self.lap_btn = ttk.Button(buttons_frame, text="Круг", command=self._on_lap, state=tk.DISABLED)
        self.lap_btn.pack(side=tk.LEFT, padx=5)

        self.reset_btn = ttk.Button(buttons_frame, text="Сброс", command=self._on_reset, state=tk.DISABLED)
        self.reset_btn.pack(side=tk.LEFT, padx=5)

        list_frame = tk.Frame(self)
        list_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10))

        self.tree = ttk.Treeview(
            list_frame,
            columns=("num", "lap", "total"),
            show="headings",
            height=10
        )
        self.tree.heading("num", text="Круг")
        self.tree.heading("lap", text="Время круга")
        self.tree.heading("total", text="Общее время")
        self.tree.column("num", width=60, anchor=tk.CENTER)
        self.tree.column("lap", width=140, anchor=tk.CENTER)
        self.tree.column("total", width=180, anchor=tk.CENTER)

        scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.tree.yview)
        self.tree.configure(yscrollcommand=scrollbar.set)

        self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

    def _configure_tags(self):
        self.tree.tag_configure("best", foreground="green", background="#ccffcc")
        self.tree.tag_configure("worst", foreground="red", background="#ffcccc")

    def _current_elapsed(self):
        if self.running:
            return self.accumulated + (time.monotonic() - self.start_time)
        return self.accumulated

    def _format_from_hs(self, total_hs, force_two_digit_minutes=False):
        minutes = total_hs // 6000
        remainder = total_hs % 6000
        seconds = remainder // 100
        hundredths = remainder % 100
        if force_two_digit_minutes or minutes < 100:
            minutes_str = f"{minutes:02d}"
        else:
            minutes_str = str(minutes)
        return f"{minutes_str}:{seconds:02d}.{hundredths:02d}"

    def _update_display(self):
        elapsed = self._current_elapsed()
        total_hs = int(round(elapsed * 100))
        display_hs = total_hs % 600000
        self.display_var.set(self._format_from_hs(display_hs, force_two_digit_minutes=True))

    def _schedule_update(self):
        if self.running:
            self._update_display()
            self.after_id = self.after(50, self._schedule_update)
        else:
            self._update_display()

    def _cancel_update(self):
        if self.after_id is not None:
            self.after_cancel(self.after_id)
            self.after_id = None

    def _on_start_stop(self):
        try:
            if self.running:
                self._stop()
            else:
                self._start()
        except Exception as e:
            messagebox.showerror("Ошибка", str(e))

    def _start(self):
        self.running = True
        self.start_time = time.monotonic()
        self.start_stop_btn.config(text="Стоп")
        self.lap_btn.config(state=tk.NORMAL)
        self.reset_btn.config(state=tk.DISABLED)
        self._schedule_update()

    def _stop(self):
        if self.running:
            self.accumulated = self._current_elapsed()
        self.running = False
        self.start_time = None
        self._cancel_update()
        self.start_stop_btn.config(text="Старт")
        self.lap_btn.config(state=tk.DISABLED)
        self.reset_btn.config(state=tk.NORMAL)
        self._update_display()

    def _on_lap(self):
        try:
            if not self.running:
                return
            current = self._current_elapsed()
            total_hs = int(round(current * 100))
            display_hs = total_hs % 600000
            if display_hs == 0:
                return
            lap_time = current - self.previous_lap_total
            lap_time_hs = int(round(lap_time * 100))
            self.lap_count += 1
            item_id = self.tree.insert(
                "",
                "end",
                values=(
                    self.lap_count,
                    self._format_from_hs(lap_time_hs),
                    self._format_from_hs(total_hs)
                )
            )
            self.lap_data[item_id] = {
                "lap_hs": lap_time_hs,
                "total_hs": total_hs
            }
            self.previous_lap_total = current
            self._update_highlights()
        except Exception as e:
            messagebox.showerror("Ошибка", str(e))

    def _update_highlights(self):
        items = self.tree.get_children()
        if len(items) < 2:
            for item in items:
                self.tree.item(item, tags=())
            return

        lap_times = [(item, self.lap_data[item]["lap_hs"]) for item in items]
        min_hs = min(lap_times, key=lambda x: x[1])[1]
        max_hs = max(lap_times, key=lambda x: x[1])[1]

        best_items = [item for item, hs in lap_times if hs == min_hs]
        worst_items = [item for item, hs in lap_times if hs == max_hs]

        for item, _ in lap_times:
            self.tree.item(item, tags=())

        best_item = best_items[0]
        worst_item = None
        for item in worst_items:
            if item != best_item:
                worst_item = item
                break
        if worst_item is None:
            if len(worst_items) > 1:
                worst_item = worst_items[1]
            else:
                worst_item = worst_items[0]

        self.tree.item(best_item, tags=("best",))
        self.tree.item(worst_item, tags=("worst",))

    def _on_reset(self):
        try:
            if self.running:
                return
            self._cancel_update()
            self.accumulated = 0.0
            self.start_time = None
            self.previous_lap_total = 0.0
            self.lap_count = 0
            self.lap_data.clear()
            for item in self.tree.get_children():
                self.tree.delete(item)
            self.display_var.set("00:00.00")
            self.lap_btn.config(state=tk.DISABLED)
            self.reset_btn.config(state=tk.DISABLED)
            self.start_stop_btn.config(text="Старт")
        except Exception as e:
            messagebox.showerror("Ошибка", str(e))

    def _on_close(self):
        self._cancel_update()
        self.destroy()


if __name__ == "__main__":
    app = StopwatchApp()
    app.mainloop()