import re
import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.lines import Line2D

import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext


def parse_log(file_path):
    t, rms, freq = [], [], []
    state_events = []
    master_events = []

    last_timestamp = None

    with open(file_path, encoding='utf-8', errors='ignore') as f:
        for line in f:

            ts_match = re.match(r'^(\w+ \d+ \d+:\d+:\d+)', line)
            if ts_match:
                try:
                    timestr = ts_match.group(1) + " 2026"
                    last_timestamp = dt.datetime.strptime(timestr, "%b %d %H:%M:%S %Y")
                except:
                    pass

            timestamp = last_timestamp

            if not timestamp:
                continue

            m = re.search(r'rms\s+(\d+).*freq\s+([+-]?\d+)', line)
            if m:
                t.append(timestamp)
                rms.append(int(m.group(1)))
                freq.append(int(m.group(2)))

            m = re.search(r'port \d+: (\w+) to (\w+)', line)
            if m:
                state_events.append((timestamp, f"{m.group(1)}→{m.group(2)}"))

            m = re.search(
                r'(selected best master clock|new foreign master)\s+([0-9a-fA-F\.:]+)',
                line
            )
            if m:
                master_events.append((timestamp, m.group(2)))

    return t, rms, freq, state_events, master_events


def plot_data(t, rms, freq, state_events, master_events, detail):

    if not t:
        messagebox.showerror("Error", "No valid RMS/freq data found.")
        return

    fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True)

    ax1.plot(t, rms, color='black')
    ax1.set_ylabel("RMS (ns)")
    ax1.grid()

    ax2.plot(t, freq, color='black')
    ax2.set_ylabel("Frequency deviation")
    ax2.set_xlabel("Time")
    ax2.grid()

    # event lines
    for ts, _ in state_events:
        ax1.axvline(ts, color='blue', linestyle='--', alpha=0.7)
        ax2.axvline(ts, color='blue', linestyle='--', alpha=0.7)

    for ts, _ in master_events:
        ax1.axvline(ts, color='red', linestyle='--', alpha=0.7)
        ax2.axvline(ts, color='red', linestyle='--', alpha=0.7)

    legend = [
        Line2D([0], [0], color='black', label='RMS/Freq'),
        Line2D([0], [0], color='blue', linestyle='--', label='State'),
        Line2D([0], [0], color='red', linestyle='--', label='Master'),
    ]
    ax1.legend(handles=legend)

    multi_day = any(d.date() != t[0].date() for d in t)

    if multi_day:
        formatter = mdates.DateFormatter('%d %H:%M')
    else:
        formatter = mdates.DateFormatter('%H:%M:%S')

    if detail == "Seconds":
        locator = mdates.SecondLocator(interval=1)
    elif detail == "5 sec":
        locator = mdates.SecondLocator(interval=5)
    elif detail == "10 sec":
        locator = mdates.SecondLocator(interval=10)
    elif detail == "30 sec":
        locator = mdates.SecondLocator(interval=30)
    elif detail == "1 min":
        locator = mdates.MinuteLocator(interval=1)
    else:
        locator = mdates.AutoDateLocator(maxticks=20)

    ax2.xaxis.set_major_locator(locator)
    ax2.xaxis.set_major_formatter(formatter)

    plt.xticks(rotation=45)
    plt.tight_layout()
    plt.show()


def open_file():
    file_path = filedialog.askopenfilename(
        title="Select log",
        filetypes=[("Log files", "*.log *.txt"), ("All files", "*.*")]
    )

    if not file_path:
        return

    detail = detail_var.get()

    t, rms, freq, state_events, master_events = parse_log(file_path)

    plot_data(t, rms, freq, state_events, master_events, detail)

    event_box.delete(1.0, tk.END)

    events = []

    for ts, label in state_events:
        events.append((ts, f"{ts} | STATE {label}"))

    for ts, label in master_events:
        events.append((ts, f"{ts} | MASTER {label}"))

    events.sort(key=lambda x: x[0])

    if events:
        for _, line in events:
            event_box.insert(tk.END, line + "\n")
    else:
        event_box.insert(tk.END, "No events found.\n")


# GUI
root = tk.Tk()
root.title("PTP Log Viewer")
root.geometry("750x550")

frame = tk.Frame(root)
frame.pack(pady=5)

tk.Button(frame, text="Open Log", command=open_file).pack(side=tk.LEFT, padx=10)

detail_var = tk.StringVar(value="Auto")

tk.OptionMenu(
    frame,
    detail_var,
    "Auto",
    "Seconds",
    "5 sec",
    "10 sec",
    "30 sec",
    "1 min"
).pack(side=tk.LEFT)

event_box = scrolledtext.ScrolledText(root)
event_box.pack(fill=tk.BOTH, expand=True)

root.mainloop()