from PIL import Image, ImageDraw, ImageFont
from pathlib import Path

OUT = Path('/home/hyein/jh-mh/장헌산업/exports')
PNG = OUT / 'work_data_erd_unified_lanes.png'
W, H = 1900, 1980
img = Image.new('RGB', (W, H), '#151718')
d = ImageDraw.Draw(img)
font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 18)
font_b = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf', 21)
font_t = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf', 34)
font_s = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 15)
font_badge = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf', 16)

BG = '#151718'
PANEL = '#181b1c'
CARD = '#202527'
HEADER = '#293033'
BORDER = '#667179'
TEXT = '#eef3f5'
MUTED = '#a8b1b7'
PK = '#f5d76e'
FK = '#87c8ff'
PEOPLE = '#55d8f4'
PROJECT = '#81e681'
ERP = '#b99bff'
CAL = '#a6b0b6'
BADGE = '#263036'

entities = {
    # left source column
    'member': (80, 210, 330, ['PK MemberNo', 'korName', 'teamName', 'rankName', 'groupCode', 'rankCode', 'isRetired']),
    'dallyproject': (80, 585, 360, ['PK id', 'FK MemberNo', 'WorkDate', 'EntryPCode', 'EntryTime / LeaveTime', 'OverTime', 'TotalHours', 'RegularHours', 'OvertimeHours']),
    'project_alias': (80, 1035, 360, ['PK projectCode', 'shortName', 'bridge/project name']),

    # shared center columns
    'site_worksheet_worker_cache': (640, 170, 430, ['PK projectCode + workDate', 'PK korName + jobType', 'workText', 'note', 'personCount', 'syncedAt']),
    'site_worksheet_record': (640, 570, 430, ['PK projectCode + workDate', 'PK memberNo + korName', 'FK memberNo', 'jobType', 'workText', 'note', 'personCount']),
    'site_worksheet_day_sync': (640, 960, 410, ['PK projectCode + workDate', 'syncedAt']),
    'site_worksheet_menu_sync': (640, 1140, 410, ['PK projectCode + workDate', 'PK selMenu', '2 = normal worksheet', '3 = tension/temp works', 'syncedAt']),

    # right output column
    'work_calendar_detail': (1350, 330, 430, ['PK id', 'source: sql / site', 'FK memberNo', 'workDate', 'projectCode', 'projectName', 'workText', 'jobType', 'hours', 'regularHours', 'overtimeHours', 'personCount']),
    'work_calendar_day': (1350, 920, 430, ['PK memberNo + workDate', 'korName / teamName / rankName', 'sqlHours', 'sqlProjectCodes', 'siteCount', 'siteProjectCodes', 'siteWorkTexts', 'hasSql / hasSite']),
    'project_yearly_summary': (1350, 1285, 430, ['VIEW project tab output', 'projectCode + yearMonth', 'memberNo / korName', 'intranetRegularHours', 'siteHours = personCount * 8', 'commonHours', 'total = intranet + site - common']),
}
heights = {k: 54 + len(v[3]) * 27 + 20 for k, v in entities.items()}

relations = [
    ('1', 'member -> dallyproject', PEOPLE),
    ('2', 'member -> site_worksheet_record', PEOPLE),
    ('3', 'project_alias -> dallyproject', PROJECT),
    ('4', 'project_alias -> worker_cache', PROJECT),
    ('5', 'day_sync: fetched project/date', CAL),
    ('6', 'menu_sync: fetched menu 2/3', CAL),
    ('7', 'worker_cache -> record', ERP),
    ('8', 'dallyproject -> calendar_detail', PEOPLE),
    ('9', 'record -> calendar_detail', ERP),
    ('10', 'project_alias -> projectName', PROJECT),
    ('11', 'calendar_detail -> calendar_day', CAL),
    ('12', 'dallyproject -> project summary', PEOPLE),
    ('13', 'record -> project summary', ERP),
]

def panel(x1, y1, x2, y2, title, color):
    d.rounded_rectangle((x1, y1, x2, y2), radius=16, fill=PANEL, outline='#2e3437', width=2)
    d.text((x1 + 24, y1 + 20), title, font=font_b, fill=color)


def card(name):
    x, y, w, fields = entities[name]
    h = heights[name]
    d.rounded_rectangle((x, y, x + w, y + h), radius=8, fill=CARD, outline=BORDER, width=2)
    d.rectangle((x, y, x + w, y + 46), fill=HEADER)
    d.line((x, y + 46, x + w, y + 46), fill=BORDER, width=1)
    d.text((x + 18, y + 12), name, font=font_b, fill=TEXT)
    yy = y + 64
    for f in fields:
        color = PK if f.startswith('PK') else FK if f.startswith('FK') else TEXT
        d.text((x + 20, yy), f, font=font_s, fill=color)
        yy += 27


def anchor(name, side, off=0):
    x, y, w, _ = entities[name]
    h = heights[name]
    if side == 'r': return (x + w, y + h // 2 + off)
    if side == 'l': return (x, y + h // 2 + off)
    if side == 't': return (x + w // 2 + off, y)
    if side == 'b': return (x + w // 2 + off, y + h)


def badge(num, x, y, color):
    d.ellipse((x - 14, y - 14, x + 14, y + 14), fill=BADGE, outline=color, width=2)
    tw = d.textlength(num, font=font_badge)
    d.text((x - tw / 2, y - 10), num, font=font_badge, fill=color)


def arrow(points, color, num=None, badge_at=None):
    d.line(points, fill=color, width=4, joint='curve')
    x1, y1 = points[-2]
    x2, y2 = points[-1]
    if abs(x2 - x1) >= abs(y2 - y1):
        tri = [(x2, y2), (x2 - 12 if x2 >= x1 else x2 + 12, y2 - 7), (x2 - 12 if x2 >= x1 else x2 + 12, y2 + 7)]
    else:
        tri = [(x2, y2), (x2 - 7, y2 - 12 if y2 >= y1 else y2 + 12), (x2 + 7, y2 - 12 if y2 >= y1 else y2 + 12)]
    d.polygon(tri, fill=color)
    if num:
        bx, by = badge_at if badge_at else points[len(points)//2]
        badge(num, bx, by, color)

# title
d.text((70, 40), 'Unified Work Data ERD', font=font_t, fill=TEXT)
d.text((72, 82), 'One diagram, separated into people flow and project flow. Numbered connectors avoid line-label overlap.', font=font_s, fill=MUTED)

# panels
panel(45, 130, 500, 1535, 'SOURCE TABLES', MUTED)
panel(585, 130, 1130, 1535, 'SHARED ERP CACHE / MATCH TABLES', MUTED)
panel(1300, 130, 1860, 1535, 'OUTPUT / VIEW TABLES', MUTED)


# connectors without text labels
arrow([anchor('member','b'), (245, 545), anchor('dallyproject','t')], PEOPLE, '1', (245, 545))
arrow([anchor('member','r',10), (555, anchor('member','r',10)[1]), (555, anchor('site_worksheet_record','l',-40)[1]), anchor('site_worksheet_record','l',-40)], PEOPLE, '2', (555, 470))
arrow([anchor('project_alias','t'), (260, 925), anchor('dallyproject','b')], PROJECT, '3', (260, 925))
arrow([anchor('project_alias','r',-20), (560, anchor('project_alias','r',-20)[1]), (560, anchor('site_worksheet_worker_cache','l',-35)[1]), anchor('site_worksheet_worker_cache','l',-35)], PROJECT, '4', (560, 825))
arrow([anchor('site_worksheet_day_sync','t'), (1110, 910), (1110, 340), anchor('site_worksheet_worker_cache','r',45)], CAL, '5', (1110, 910))
arrow([anchor('site_worksheet_menu_sync','t'), (1160, 1120), (1160, 370), anchor('site_worksheet_worker_cache','r',90)], CAL, '6', (1160, 1120))
arrow([anchor('site_worksheet_worker_cache','b'), (855, 520), anchor('site_worksheet_record','t')], ERP, '7', (855, 520))
arrow([anchor('dallyproject','r',-30), (1235, anchor('dallyproject','r',-30)[1]), (1235, anchor('work_calendar_detail','l',-80)[1]), anchor('work_calendar_detail','l',-80)], PEOPLE, '8', (1235, 610))
arrow([anchor('site_worksheet_record','r'), (1240, anchor('site_worksheet_record','r')[1]), (1240, anchor('work_calendar_detail','l',40)[1]), anchor('work_calendar_detail','l',40)], ERP, '9', (1240, 690))
arrow([anchor('project_alias','r',35), (1200, anchor('project_alias','r',35)[1]), (1200, anchor('work_calendar_detail','l',95)[1]), anchor('work_calendar_detail','l',95)], PROJECT, '10', (1200, 1030))
arrow([anchor('work_calendar_detail','b'), (1565, 880), anchor('work_calendar_day','t')], CAL, '11', (1565, 880))
arrow([anchor('dallyproject','r',35), (1280, anchor('dallyproject','r',35)[1]), (1280, anchor('project_yearly_summary','l',-45)[1]), anchor('project_yearly_summary','l',-45)], PEOPLE, '12', (1280, 800))
arrow([anchor('site_worksheet_record','r',55), (1265, anchor('site_worksheet_record','r',55)[1]), (1265, anchor('project_yearly_summary','l',30)[1]), anchor('project_yearly_summary','l',30)], ERP, '13', (1265, 1185))

# cards
for name in entities:
    card(name)

# connector legend bottom
legend_x, legend_y = 70, 1590
d.rounded_rectangle((legend_x, legend_y, 1830, 1775), radius=10, fill='#1d2123', outline='#3a4247')
d.text((legend_x + 20, legend_y + 16), 'CONNECTORS', font=font_b, fill=TEXT)
col_w = 570
for idx, (num, text, color) in enumerate(relations):
    col = idx // 5
    row = idx % 5
    x = legend_x + 28 + col * col_w
    y = legend_y + 55 + row * 34
    badge(num, x, y + 8, color)
    d.text((x + 28, y), text, font=font_s, fill=TEXT)

# mini flow labels
d.rounded_rectangle((70, 1810, 1830, 1850), radius=8, fill='#1d2123', outline='#3a4247')
d.text((90, 1820), 'People flow: member + dallyproject + matched ERP rows -> calendar  |  Project flow: dallyproject + matched ERP rows -> project summary', font=font_s, fill=MUTED)

img.save(PNG)
print(PNG)
