import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch
import matplotlib.patheffects as pe

# ── colour palette ──────────────────────────────────────────────────────────
C = {
    "admin":    "#4A90D9",
    "user":     "#2ECC71",
    "village":  "#E74C3C",
    "announce": "#F39C12",
    "project":  "#9B59B6",
    "division": "#1ABC9C",
    "discuss":  "#E67E22",
    "other":    "#95A5A6",
    "new":      "#E74C3C",
}

GROUPS = {
    "Admin":        (["AdminRole","Admin"],                          C["admin"]),
    "User":         (["UserRole","User","TokenDeviceUser","UserLog"],C["user"]),
    "Village":      (["Village","ColorTheme","BannerImage"],         C["village"]),
    "Announcement": (["Announcement","AnnouncementMember",
                      "AnnouncementFile"],                           C["announce"]),
    "Project":      (["Project","ProjectMember","ProjectFile",
                      "ProjectLink","ProjectTask","ProjectTaskFile",
                      "ProjectTaskDetail"],                          C["project"]),
    "Division":     (["Division","DivisionMember","DivisionProject",
                      "DivisionProjectMember","DivisionProjectFile",
                      "DivisionProjectLink",
                      "DivisionProjectTask","DivisionProjectTaskFile",
                      "DivisionProjectTaskDetail",
                      "DivisionDisscussion","DivisionDisscussionComment",
                      "DivisionDiscussionFile",
                      "DivisionDocumentFolderFile","DivisionDocumentShare",
                      "DivisionCalendar","DivisionCalendarReminder",
                      "DivisionCalendarMember",
                      "ContainerFileDivision"],                      C["division"]),
    "Discussion":   (["Discussion","DiscussionMember",
                      "DiscussionComment","DiscussionFile"],         C["discuss"]),
    "Other":        (["Group","Position","Notifications",
                      "Subscribe","Setting","ContainerImage"],       C["other"]),
}

NEW_MODELS = {"ProjectTaskFile", "DivisionProjectTaskFile"}

# ── relations (src, dst, label) ─────────────────────────────────────────────
RELATIONS = [
    # Admin
    ("AdminRole","Admin","1-N"),
    # User
    ("UserRole","User","1-N"),
    ("Village","User","1-N"),
    ("Group","User","1-N"),
    ("Position","User","0..1-N"),
    # Village
    ("Village","Group","1-N"),
    ("Village","Announcement","1-N"),
    ("Village","Project","1-N"),
    ("Village","Division","1-N"),
    ("Village","Discussion","1-N"),
    ("Village","ColorTheme","1-N"),
    ("Village","BannerImage","1-N"),
    # Group
    ("Group","Position","1-N"),
    ("Group","Project","1-N"),
    ("Group","Division","1-N"),
    ("Group","AnnouncementMember","1-N"),
    ("Group","Discussion","1-N"),
    # Announcement
    ("Announcement","AnnouncementMember","1-N"),
    ("Announcement","AnnouncementFile","1-N"),
    ("Division","AnnouncementMember","1-N"),
    # Project
    ("Project","ProjectMember","1-N"),
    ("Project","ProjectFile","1-N"),
    ("Project","ProjectLink","1-N"),
    ("Project","ProjectTask","1-N"),
    ("ProjectTask","ProjectTaskDetail","1-N"),
    ("ProjectTask","ProjectTaskFile","1-N"),
    ("ProjectFile","ProjectTaskFile","1-N"),
    # Division
    ("Division","DivisionMember","1-N"),
    ("Division","DivisionProject","1-N"),
    ("DivisionProject","DivisionProjectMember","1-N"),
    ("DivisionProject","DivisionProjectFile","1-N"),
    ("DivisionProject","DivisionProjectLink","1-N"),
    ("DivisionProject","DivisionProjectTask","1-N"),
    ("DivisionProjectTask","DivisionProjectTaskDetail","1-N"),
    ("DivisionProjectTask","DivisionProjectTaskFile","1-N"),
    ("DivisionProjectFile","DivisionProjectTaskFile","1-N"),
    ("ContainerFileDivision","DivisionProjectFile","1-N"),
    ("Division","DivisionDisscussion","1-N"),
    ("DivisionDisscussion","DivisionDisscussionComment","1-N"),
    ("DivisionDisscussion","DivisionDiscussionFile","1-N"),
    ("Division","DivisionDocumentFolderFile","1-N"),
    ("DivisionDocumentFolderFile","DivisionDocumentShare","1-N"),
    ("Division","DivisionCalendar","1-N"),
    ("DivisionCalendar","DivisionCalendarReminder","1-N"),
    ("DivisionCalendar","DivisionCalendarMember","1-N"),
    # Discussion
    ("Discussion","DiscussionMember","1-N"),
    ("Discussion","DiscussionComment","1-N"),
    ("Discussion","DiscussionFile","1-N"),
    # Other
    ("User","Notifications","1-N"),
    ("User","Subscribe","1-1"),
    ("User","TokenDeviceUser","1-N"),
    ("User","UserLog","1-N"),
]

# ── layout: group boxes ──────────────────────────────────────────────────────
# (x, y, w, h)  in data coordinates (canvas = 0..100 x 0..100)
LAYOUT = {
    "Admin":        ( 1, 88, 18, 10),
    "User":         ( 1, 68, 22, 18),
    "Village":      (26, 88, 22, 10),
    "Other":        (51, 88, 22, 10),
    "Announcement": (76, 80, 22, 18),
    "Project":      ( 1,  2, 38, 48),
    "Division":     (41,  2, 38, 64),
    "Discussion":   (81,  2, 17, 30),
}

def group_center(gname):
    x,y,w,h = LAYOUT[gname]
    return x+w/2, y+h/2

def model_pos(model):
    for gname,(models,_) in GROUPS.items():
        if model in models:
            x,y,w,h = LAYOUT[gname]
            idx = models.index(model)
            n   = len(models)
            cols = max(1, min(3, n))
            rows = (n + cols - 1) // cols
            col  = idx % cols
            row  = idx // cols
            mx   = x + 1.5 + col * (w-2) / cols
            my   = y + h - 2.5 - row * (h-1.5) / rows
            return mx, my
    return 50, 50

# ── draw ─────────────────────────────────────────────────────────────────────
fig, ax = plt.subplots(figsize=(28, 22))
ax.set_xlim(0, 100)
ax.set_ylim(0, 100)
ax.axis("off")
fig.patch.set_facecolor("#F0F4F8")
ax.set_facecolor("#F0F4F8")

ax.set_title("ERD – Sistem Desa Mandiri", fontsize=20, fontweight="bold",
             color="#2C3E50", pad=14)

# group boxes
for gname, (models, color) in GROUPS.items():
    x,y,w,h = LAYOUT[gname]
    rect = FancyBboxPatch((x,y), w, h,
                          boxstyle="round,pad=0.3",
                          linewidth=2, edgecolor=color,
                          facecolor=color+"22")
    ax.add_patch(rect)
    ax.text(x+w/2, y+h-0.6, gname, ha="center", va="top",
            fontsize=9, fontweight="bold", color=color)

# model nodes
for gname, (models, color) in GROUPS.items():
    for m in models:
        mx, my = model_pos(m)
        is_new = m in NEW_MODELS
        fc = "#FFECEC" if is_new else "white"
        ec = C["new"] if is_new else color
        lw = 2.5 if is_new else 1.5
        node = FancyBboxPatch((mx-3.2, my-0.85), 6.4, 1.7,
                              boxstyle="round,pad=0.2",
                              linewidth=lw, edgecolor=ec, facecolor=fc)
        ax.add_patch(node)
        fw = "bold" if is_new else "normal"
        ax.text(mx, my, m, ha="center", va="center",
                fontsize=6.2, color="#2C3E50", fontweight=fw)

# relations
drawn = set()
for src, dst, lbl in RELATIONS:
    key = tuple(sorted([src,dst]))
    sx, sy = model_pos(src)
    dx, dy = model_pos(dst)
    color  = "#BDC3C7"
    is_new_rel = src in NEW_MODELS or dst in NEW_MODELS
    if is_new_rel:
        color = C["new"]
    ax.annotate("", xy=(dx,dy), xytext=(sx,sy),
                arrowprops=dict(arrowstyle="-|>", color=color,
                                lw=1.5 if is_new_rel else 0.8,
                                connectionstyle="arc3,rad=0.05"))
    if key not in drawn:
        mx2, my2 = (sx+dx)/2, (sy+dy)/2
        ax.text(mx2, my2+0.4, lbl, ha="center", va="bottom",
                fontsize=4.5, color=color, alpha=0.85)
        drawn.add(key)

# legend
leg_items = [
    mpatches.Patch(facecolor="#FFECEC", edgecolor=C["new"], linewidth=2,
                   label="Model Baru"),
    mpatches.Patch(facecolor="white",   edgecolor="#BDC3C7", label="Model Lama"),
]
ax.legend(handles=leg_items, loc="lower right", fontsize=9,
          framealpha=0.9, edgecolor="#BDC3C7")

out = "/Users/wibu04/Documents/Projects/sistem-desa-mandiri/erd.png"
plt.savefig(out, dpi=150, bbox_inches="tight", facecolor=fig.get_facecolor())
plt.close()
print("Saved:", out)
