import json
import socket
import sys
import time
from pathlib import Path
import tkinter as tk
from tkinter import ttk, messagebox, filedialog

ROOT = Path(__file__).resolve().parent
DATA_DIR = ROOT / "data"
TARGETS_FILE = DATA_DIR / "targets.json"
REPORT_FILE = DATA_DIR / "latest_report.json"

DEFAULT_TARGETS = [
    {"host": "localhost", "port": 80, "label": "Web Lokal"},
    {"host": "localhost", "port": 22, "label": "SSH Lokal"},
    {"host": "8.8.8.8", "port": 53, "label": "DNS Google"},
]


def ensure_files():
    DATA_DIR.mkdir(exist_ok=True)
    if not TARGETS_FILE.exists():
        TARGETS_FILE.write_text(json.dumps(DEFAULT_TARGETS, indent=2), encoding="utf-8")


def load_targets():
    ensure_files()
    return json.loads(TARGETS_FILE.read_text(encoding="utf-8"))


def save_targets(targets):
    TARGETS_FILE.write_text(json.dumps(targets, indent=2), encoding="utf-8")


def check_target(host: str, port: int):
    start = time.perf_counter()
    try:
        with socket.create_connection((host, port), timeout=1.5):
            latency = round((time.perf_counter() - start) * 1000, 2)
            return {"reachable": True, "latency_ms": latency, "error": ""}
    except Exception as exc:
        latency = round((time.perf_counter() - start) * 1000, 2)
        return {"reachable": False, "latency_ms": latency, "error": str(exc)}


def build_report(targets):
    rows = []
    ok = 0
    for target in targets:
        result = check_target(target["host"], int(target["port"]))
        if result["reachable"]:
            ok += 1
        rows.append({
            "label": target["label"],
            "host": target["host"],
            "port": int(target["port"]),
            **result,
        })
    report = {
        "checked_at": time.strftime("%Y-%m-%d %H:%M:%S"),
        "total_targets": len(rows),
        "reachable_targets": ok,
        "failed_targets": len(rows) - ok,
        "results": rows,
    }
    REPORT_FILE.write_text(json.dumps(report, indent=2), encoding="utf-8")
    return report


class App(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("NetOps Monitor Python")
        self.geometry("1080x720")
        self.minsize(980, 640)
        self.configure(bg="#eef4fb")
        self.targets = load_targets()

        title = tk.Label(
            self,
            text="NetOps Monitor Python",
            font=("Segoe UI", 22, "bold"),
            bg="#0f172a",
            fg="white",
            pady=14,
        )
        title.pack(fill="x")

        wrapper = tk.Frame(self, bg="#eef4fb", padx=12, pady=12)
        wrapper.pack(fill="both", expand=True)

        top = tk.Frame(wrapper, bg="#eef4fb")
        top.pack(fill="x", pady=(0, 10))

        tk.Label(top, text="Host", bg="#eef4fb").grid(row=0, column=0, sticky="w")
        self.host_var = tk.StringVar(value="localhost")
        tk.Entry(top, textvariable=self.host_var, width=22).grid(row=1, column=0, padx=(0, 8))

        tk.Label(top, text="Port", bg="#eef4fb").grid(row=0, column=1, sticky="w")
        self.port_var = tk.StringVar(value="80")
        tk.Entry(top, textvariable=self.port_var, width=10).grid(row=1, column=1, padx=(0, 8))

        tk.Label(top, text="Label", bg="#eef4fb").grid(row=0, column=2, sticky="w")
        self.label_var = tk.StringVar(value="Target Baru")
        tk.Entry(top, textvariable=self.label_var, width=26).grid(row=1, column=2, padx=(0, 8))

        tk.Button(top, text="Tambah Target", command=self.add_target, bg="#2563eb", fg="white").grid(row=1, column=3, padx=(0, 8))
        tk.Button(top, text="Jalankan Pengecekan", command=self.run_checks, bg="#0f766e", fg="white").grid(row=1, column=4, padx=(0, 8))
        tk.Button(top, text="Simpan Target", command=self.save_all, bg="#475569", fg="white").grid(row=1, column=5, padx=(0, 8))
        tk.Button(top, text="Ekspor Laporan", command=self.export_report, bg="#7c3aed", fg="white").grid(row=1, column=6)

        mid = tk.Frame(wrapper, bg="#eef4fb")
        mid.pack(fill="both", expand=True)

        self.tree = ttk.Treeview(mid, columns=("label", "host", "port", "status", "latency", "error"), show="headings")
        for col, width in [("label", 180), ("host", 160), ("port", 80), ("status", 100), ("latency", 110), ("error", 360)]:
            self.tree.heading(col, text=col.upper())
            self.tree.column(col, width=width, anchor="w")
        self.tree.pack(side="left", fill="both", expand=True)

        scroll = ttk.Scrollbar(mid, orient="vertical", command=self.tree.yview)
        self.tree.configure(yscrollcommand=scroll.set)
        scroll.pack(side="right", fill="y")

        bottom = tk.Frame(wrapper, bg="#eef4fb")
        bottom.pack(fill="x", pady=(10, 0))

        self.summary_var = tk.StringVar(value="Belum ada pengecekan.")
        tk.Label(bottom, textvariable=self.summary_var, bg="#eef4fb", font=("Segoe UI", 10, "bold")).pack(side="left")
        tk.Button(bottom, text="Hapus Target Terpilih", command=self.delete_selected, bg="#dc2626", fg="white").pack(side="right")

        self.refresh_table()

    def refresh_table(self, report=None):
        self.tree.delete(*self.tree.get_children())
        if report:
            for row in report["results"]:
                self.tree.insert("", "end", values=(
                    row["label"], row["host"], row["port"],
                    "UP" if row["reachable"] else "DOWN",
                    row["latency_ms"], row["error"]
                ))
            self.summary_var.set(
                f"Terakhir cek: {report['checked_at']} | UP: {report['reachable_targets']} / {report['total_targets']}"
            )
        else:
            for row in self.targets:
                self.tree.insert("", "end", values=(row["label"], row["host"], row["port"], "-", "-", "Belum dicek"))
            self.summary_var.set(f"Total target tersimpan: {len(self.targets)}")

    def add_target(self):
        try:
            port = int(self.port_var.get().strip())
        except ValueError:
            messagebox.showerror("Port Salah", "Port harus berupa angka.")
            return
        host = self.host_var.get().strip()
        label = self.label_var.get().strip() or host
        if not host:
            messagebox.showerror("Host Kosong", "Host wajib diisi.")
            return
        self.targets.append({"host": host, "port": port, "label": label})
        self.refresh_table()
        self.save_all()

    def save_all(self):
        save_targets(self.targets)
        self.summary_var.set("Target berhasil disimpan.")

    def run_checks(self):
        report = build_report(self.targets)
        self.refresh_table(report)
        messagebox.showinfo("Selesai", "Pengecekan jaringan selesai.")

    def export_report(self):
        if not REPORT_FILE.exists():
            report = build_report(self.targets)
        else:
            report = json.loads(REPORT_FILE.read_text(encoding="utf-8"))
        dest = filedialog.asksaveasfilename(
            title="Simpan laporan JSON",
            defaultextension=".json",
            filetypes=[("JSON", "*.json")]
        )
        if not dest:
            return
        Path(dest).write_text(json.dumps(report, indent=2), encoding="utf-8")
        messagebox.showinfo("Berhasil", f"Laporan disimpan ke:\n{dest}")

    def delete_selected(self):
        selected = self.tree.selection()
        if not selected:
            return
        idx = self.tree.index(selected[0])
        if 0 <= idx < len(self.targets):
            self.targets.pop(idx)
            self.save_all()
            self.refresh_table()

def smoke_test():
    ensure_files()
    report = build_report(load_targets())
    print(json.dumps({
        "app": "netops-monitor-python",
        "total_targets": report["total_targets"],
        "report_file": str(REPORT_FILE.name),
    }, indent=2))


if __name__ == "__main__":
    if "--smoke-test" in sys.argv:
        smoke_test()
    else:
        ensure_files()
        App().mainloop()
