"""Pelacak kebiasaan: satu jendela, satu periode, JSON lokal."""
import json
from pathlib import Path
import tkinter as tk
from tkinter import ttk, messagebox

DEFAULT = [{"id": 1, "title": "Membaca", "done": False},
           {"id": 2, "title": "Latihan soal", "done": False},
           {"id": 3, "title": "Merapikan catatan", "done": False}]


def load(path):
    rows = [dict(row) for row in DEFAULT]
    try:
        saved = json.loads(Path(path).read_text(encoding="utf-8"))
    except FileNotFoundError:
        return rows
    if not isinstance(saved, list) or len(saved) != len(rows):
        raise ValueError("Dibutuhkan tiga status kebiasaan.")
    by_id = {}
    for row in saved:
        if not isinstance(row, dict) or type(row.get("id")) is not int or type(row.get("done")) is not bool:
            raise ValueError("ID atau status tidak valid.")
        if row["id"] in by_id:
            raise ValueError("ID ganda.")
        by_id[row["id"]] = row["done"]
    if set(by_id) != {row["id"] for row in rows}:
        raise ValueError("ID kebiasaan tidak cocok.")
    for row in rows:
        row["done"] = by_id[row["id"]]
    return rows


def summary(rows):
    return sum(row["done"] for row in rows), len(rows)


def save(path, rows):
    path = Path(path)
    payload = [{"id": row["id"], "done": row["done"]} for row in rows]
    temporary = path.with_suffix(path.suffix + ".tmp")
    temporary.write_text(json.dumps(payload, indent=2), encoding="utf-8")
    temporary.replace(path)


def build_window(root, path):
    rows = load(path)
    root.title("Pelacak Kebiasaan Belajar")
    root.geometry("480x300")
    status = tk.StringVar(root)
    variables = {}
    checks = {}
    ttk.Label(root, text="Checklist satu periode belajar").pack(pady=14)

    def render():
        for row in rows:
            variables[row["id"]].set(row["done"])
        done, total = summary(rows)
        status.set(f"Selesai {done}/{total}")

    def toggle(ident):
        for row in rows:
            if row["id"] == ident:
                row["done"] = variables[ident].get()
        render()

    for row in rows:
        ident = row["id"]
        variables[ident] = tk.BooleanVar(root, value=row["done"])
        check = ttk.Checkbutton(root, text=row["title"], variable=variables[ident],
                                command=lambda ident=ident: toggle(ident))
        check.pack(anchor="w", padx=24, pady=4)
        checks[ident] = check

    def persist():
        try:
            save(path, rows)
            status.set("Status tersimpan.")
        except OSError as error:
            messagebox.showerror("Simpan", str(error), parent=root)

    def reload():
        try:
            loaded = load(path)
            rows[:] = loaded
            render()
        except (ValueError, OSError) as error:
            messagebox.showerror("Muat: file dipertahankan", str(error), parent=root)

    def reset():
        for row in rows:
            row["done"] = False
        render()

    bar = ttk.Frame(root)
    bar.pack(pady=12)
    buttons = {}
    for label, handler in [("Simpan", persist), ("Muat", reload), ("Reset", reset)]:
        button = ttk.Button(bar, text=label, command=handler)
        button.pack(side="left", padx=4)
        buttons[label] = button
    ttk.Label(root, textvariable=status).pack()
    ttk.Label(root, text="Simpan sebelum menutup. Reset memulai periode baru.").pack(pady=6)
    render()
    return {"rows": rows, "checks": checks, "buttons": buttons, "status": status}


def main():
    root = tk.Tk()
    try:
        build_window(root, Path(__file__).with_name("habits.json"))
    except (ValueError, OSError) as error:
        messagebox.showerror("Data tidak dibuka; file dipertahankan", str(error), parent=root)
        root.destroy()
        return
    root.mainloop()


if __name__ == "__main__":
    main()
