#!/usr/bin/env python3
"""Generate 4 process modeling diagrams (BPMN, UML Activity, EPC, Flowchart).

all representing the same process: "Obsluga reklamacji" (Complaint Handling).
Output: A4-compatible, black & white, laser-printer-friendly PNG files.
"""

import matplotlib as mpl

mpl.use("Agg")
from pathlib import Path

import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch, Polygon
from matplotlib.path import Path as MplPath
import matplotlib.pyplot as plt

# --- Common settings ---
DPI = 300
BG_COLOR = "white"
LINE_COLOR = "black"
FONT_SIZE = 9
TITLE_SIZE = 14
OUTPUT_DIR = str(Path(__file__).resolve().parent / "img")
Path(OUTPUT_DIR).mkdir(parents=True, exist_ok=True)


def draw_arrow(ax, x1, y1, x2, y2) -> None:
    """Draw arrow."""
    ax.annotate(
        "",
        xy=(x2, y2),
        xytext=(x1, y1),
        arrowprops={"arrowstyle": "->", "color": LINE_COLOR, "lw": 1.3},
    )


def draw_line(ax, x1, y1, x2, y2) -> None:
    """Draw line."""
    ax.plot([x1, x2], [y1, y2], color=LINE_COLOR, lw=1.3, solid_capstyle="round")


def draw_rounded_rect(
    ax, x, y, w, h, text, fill="white", lw=1.5, fontsize=FONT_SIZE
) -> None:
    """Draw rounded rect."""
    rect = FancyBboxPatch(
        (x - w / 2, y - h / 2),
        w,
        h,
        boxstyle="round,pad=0.3",
        linewidth=lw,
        edgecolor=LINE_COLOR,
        facecolor=fill,
    )
    ax.add_patch(rect)
    ax.text(x, y, text, ha="center", va="center", fontsize=fontsize)


def draw_diamond(ax, x, y, size, text="", fill="white", fontsize=8) -> None:
    """Draw diamond."""
    s = size
    diamond = Polygon(
        [(x, y + s), (x + s, y), (x, y - s), (x - s, y)],
        closed=True,
        linewidth=1.5,
        edgecolor=LINE_COLOR,
        facecolor=fill,
    )
    ax.add_patch(diamond)
    if text:
        ax.text(
            x, y, text, ha="center", va="center", fontsize=fontsize, fontweight="bold"
        )


# =========================================================================
# 1. BPMN 2.0 Diagram
# =========================================================================
def generate_bpmn() -> None:
    """Generate bpmn."""
    fig, ax = plt.subplots(figsize=(11, 7.5))
    ax.set_xlim(0, 110)
    ax.set_ylim(0, 75)
    ax.set_aspect("equal")
    ax.axis("off")
    fig.patch.set_facecolor(BG_COLOR)
    ax.set_title(
        "BPMN 2.0 \u2014 Obs\u0142uga reklamacji",
        fontsize=TITLE_SIZE,
        fontweight="bold",
        pad=12,
    )

    # --- Pool outline ---
    pool_x, pool_y, pool_w, pool_h = 3, 3, 104, 68
    ax.add_patch(
        plt.Rectangle(
            (pool_x, pool_y),
            pool_w,
            pool_h,
            lw=2,
            edgecolor=LINE_COLOR,
            facecolor="white",
        )
    )

    # Pool label
    label_strip = pool_x + 4
    ax.plot(
        [label_strip, label_strip], [pool_y, pool_y + pool_h], color=LINE_COLOR, lw=1.5
    )
    ax.text(
        pool_x + 2,
        pool_y + pool_h / 2,
        "FIRMA",
        fontsize=11,
        fontweight="bold",
        rotation=90,
        ha="center",
        va="center",
    )

    # --- Lanes ---
    lane_top = pool_y + pool_h
    lane_mid1 = pool_y + pool_h * 2 / 3
    lane_mid2 = pool_y + pool_h * 1 / 3

    ax.plot(
        [label_strip, pool_x + pool_w], [lane_mid1, lane_mid1], color=LINE_COLOR, lw=1
    )
    ax.plot(
        [label_strip, pool_x + pool_w], [lane_mid2, lane_mid2], color=LINE_COLOR, lw=1
    )

    y_bok = (lane_top + lane_mid1) / 2
    y_jak = (lane_mid1 + lane_mid2) / 2
    y_mag = (lane_mid2 + pool_y) / 2

    ax.text(
        label_strip + 2.5,
        y_bok,
        "BOK",
        fontsize=8,
        ha="center",
        va="center",
        rotation=90,
        fontstyle="italic",
    )
    ax.text(
        label_strip + 2.5,
        y_jak,
        "Jako\u015b\u0107",
        fontsize=8,
        ha="center",
        va="center",
        rotation=90,
        fontstyle="italic",
    )
    ax.text(
        label_strip + 2.5,
        y_mag,
        "Magazyn",
        fontsize=8,
        ha="center",
        va="center",
        rotation=90,
        fontstyle="italic",
    )

    content_left = label_strip + 5

    # --- Elements ---
    # Start event
    sx = content_left + 4
    ax.add_patch(
        plt.Circle((sx, y_bok), 2, lw=2, edgecolor=LINE_COLOR, facecolor="white")
    )
    ax.text(sx, y_bok - 3.5, "Reklamacja\nwp\u0142ywa", fontsize=6, ha="center")

    # Task 1: Przyjmij zg\u0142oszenie (BOK)
    t1x = sx + 14
    draw_rounded_rect(ax, t1x, y_bok, 14, 6, "Przyjmij\nzg\u0142oszenie")
    draw_arrow(ax, sx + 2, y_bok, t1x - 7, y_bok)

    # Task 2: Zweryfikuj zasadno\u015b\u0107 (Jako\u015b\u0107) \u2014 elbow routing
    t2x = t1x + 18
    draw_rounded_rect(ax, t2x, y_jak, 14, 6, "Zweryfikuj\nzasadno\u015b\u0107")
    elbow_x = t1x + 10
    draw_line(ax, t1x + 7, y_bok, elbow_x, y_bok)
    draw_line(ax, elbow_x, y_bok, elbow_x, y_jak)
    draw_arrow(ax, elbow_x, y_jak, t2x - 7, y_jak)

    # XOR Gateway (split)
    gx = t2x + 14
    draw_diamond(ax, gx, y_jak, 3.5, "X")
    draw_arrow(ax, t2x + 7, y_jak, gx - 3.5, y_jak)

    # YES: down to Magazyn
    t3x = gx + 14
    draw_rounded_rect(ax, t3x, y_mag, 14, 6, "Przygotuj\nwymian\u0119/zwrot")
    draw_line(ax, gx, y_jak - 3.5, gx, y_mag)
    draw_arrow(ax, gx, y_mag, t3x - 7, y_mag)
    ax.text(gx + 1.5, y_jak - 6, "Tak", fontsize=7, ha="left")

    # NO: right in Jako\u015b\u0107
    t4x = gx + 14
    draw_rounded_rect(ax, t4x, y_jak, 14, 6, "Odrzu\u0107\nreklamacj\u0119")
    draw_arrow(ax, gx + 3.5, y_jak, t4x - 7, y_jak)
    ax.text(gx + 4, y_jak + 2, "Nie", fontsize=7, ha="left")

    # XOR merge (in BOK)
    mx = t4x + 14
    draw_diamond(ax, mx, y_bok, 3.5, "X")
    # From Odrzu\u0107 up to merge
    draw_line(ax, t4x + 7, y_jak, mx, y_jak)
    draw_arrow(ax, mx, y_jak, mx, y_bok - 3.5)
    # From Przygotuj wymian\u0119 up to merge (offset to avoid overlap)
    draw_line(ax, t3x + 7, y_mag, mx - 4, y_mag)
    draw_line(ax, mx - 4, y_mag, mx - 4, y_bok)
    draw_arrow(ax, mx - 4, y_bok, mx - 3.5, y_bok)

    # Task 5: Powiadom klienta (BOK)
    t5x = mx + 13
    draw_rounded_rect(ax, t5x, y_bok, 14, 6, "Powiadom\nklienta")
    draw_arrow(ax, mx + 3.5, y_bok, t5x - 7, y_bok)

    # End event
    ex = t5x + 12
    ax.add_patch(
        plt.Circle((ex, y_bok), 2, lw=3, edgecolor=LINE_COLOR, facecolor="white")
    )
    draw_arrow(ax, t5x + 7, y_bok, ex - 2, y_bok)
    ax.text(ex, y_bok - 3.5, "Koniec", fontsize=6, ha="center")

    # --- Legend ---
    ly = 1
    ax.text(12, ly, "Legenda:", fontsize=7, fontweight="bold", va="center")
    ax.add_patch(plt.Circle((22, ly), 1, lw=2, edgecolor=LINE_COLOR, facecolor="white"))
    ax.text(24, ly, "Start", fontsize=6, va="center")
    ax.add_patch(plt.Circle((30, ly), 1, lw=3, edgecolor=LINE_COLOR, facecolor="white"))
    ax.text(32, ly, "Koniec", fontsize=6, va="center")
    draw_diamond(ax, 40, ly, 1.5, "X", fontsize=5)
    ax.text(43, ly, "Bramka XOR", fontsize=6, va="center")
    draw_rounded_rect(ax, 58, ly, 7, 2.5, "Zadanie", fontsize=6)
    ax.text(65, ly, "Sequence Flow \u2192", fontsize=6, va="center")

    fig.tight_layout()
    fig.savefig(
        str(Path(OUTPUT_DIR) / "bpmn_reklamacja.png"),
        dpi=DPI,
        facecolor="white",
        bbox_inches="tight",
    )
    plt.close(fig)
    print("  OK BPMN saved")


# =========================================================================
# 2. UML Activity Diagram
# =========================================================================
def generate_uml_activity() -> None:
    """Generate uml activity."""
    fig, ax = plt.subplots(figsize=(8.27, 10))
    ax.set_xlim(0, 100)
    ax.set_ylim(0, 100)
    ax.set_aspect("equal")
    ax.axis("off")
    fig.patch.set_facecolor(BG_COLOR)
    ax.set_title(
        "UML Activity Diagram \u2014 Obs\u0142uga reklamacji",
        fontsize=TITLE_SIZE,
        fontweight="bold",
        pad=12,
    )

    cx = 50
    y = 93
    step = 11

    # Initial node
    ax.add_patch(plt.Circle((cx, y), 1.8, facecolor="black", edgecolor="black"))

    # Action 1
    y -= step
    draw_rounded_rect(ax, cx, y, 28, 6, "Przyjmij zg\u0142oszenie reklamacji")
    draw_arrow(ax, cx, y + step - 1.8, cx, y + 3)

    # Action 2
    y -= step
    draw_rounded_rect(ax, cx, y, 28, 6, "Zweryfikuj zasadno\u015b\u0107")
    draw_arrow(ax, cx, y + step - 3, cx, y + 3)

    # Decision
    y -= step
    draw_diamond(ax, cx, y, 4)
    draw_arrow(ax, cx, y + step - 3, cx, y + 4)
    ax.text(cx + 6, y + 5, "[zasadna?]", fontsize=8, fontstyle="italic")

    dec_y = y
    branch_y = dec_y - step

    # Left [tak]
    left_x = cx - 24
    draw_rounded_rect(ax, left_x, branch_y, 22, 6, "Przygotuj\nwymian\u0119/zwrot")
    draw_line(ax, cx - 4, dec_y, left_x, dec_y)
    draw_arrow(ax, left_x, dec_y, left_x, branch_y + 3)
    ax.text(left_x + 2, dec_y + 1.5, "[tak]", fontsize=8, fontstyle="italic")

    # Right [nie]
    right_x = cx + 24
    draw_rounded_rect(ax, right_x, branch_y, 22, 6, "Odrzu\u0107\nreklamacj\u0119")
    draw_line(ax, cx + 4, dec_y, right_x, dec_y)
    draw_arrow(ax, right_x, dec_y, right_x, branch_y + 3)
    ax.text(right_x - 12, dec_y + 1.5, "[nie]", fontsize=8, fontstyle="italic")

    # Merge
    merge_y = branch_y - step
    draw_diamond(ax, cx, merge_y, 4)
    draw_line(ax, left_x, branch_y - 3, left_x, merge_y)
    draw_line(ax, left_x, merge_y, cx - 4, merge_y)
    draw_line(ax, right_x, branch_y - 3, right_x, merge_y)
    draw_line(ax, right_x, merge_y, cx + 4, merge_y)

    # Action: Powiadom
    y = merge_y - step
    draw_rounded_rect(ax, cx, y, 28, 6, "Powiadom klienta")
    draw_arrow(ax, cx, merge_y - 4, cx, y + 3)

    # Final node
    ey = y - step
    ax.add_patch(plt.Circle((cx, ey), 2.5, lw=2, facecolor="white", edgecolor="black"))
    ax.add_patch(plt.Circle((cx, ey), 1.5, facecolor="black", edgecolor="black"))
    draw_arrow(ax, cx, y - 3, cx, ey + 2.5)

    # Legend
    ly = 5
    ax.add_patch(plt.Circle((12, ly), 1.2, facecolor="black", edgecolor="black"))
    ax.text(15, ly, "= Pocz\u0105tek", fontsize=7, va="center")
    ax.add_patch(plt.Circle((32, ly), 1.3, lw=2, facecolor="white", edgecolor="black"))
    ax.add_patch(plt.Circle((32, ly), 0.8, facecolor="black", edgecolor="black"))
    ax.text(35, ly, "= Koniec", fontsize=7, va="center")
    draw_diamond(ax, 50, ly, 1.5)
    ax.text(53, ly, "= Decyzja/Merge", fontsize=7, va="center")
    draw_rounded_rect(ax, 78, ly, 9, 3, "Akcja", fontsize=7)

    fig.tight_layout()
    fig.savefig(
        str(Path(OUTPUT_DIR) / "uml_activity_reklamacja.png"),
        dpi=DPI,
        facecolor="white",
        bbox_inches="tight",
    )
    plt.close(fig)
    print("  OK UML Activity saved")


# =========================================================================
# 3. EPC (Event-driven Process Chain)
# =========================================================================
def generate_epc() -> None:
    """Generate epc."""
    fig, ax = plt.subplots(figsize=(8.27, 11))
    ax.set_xlim(0, 100)
    ax.set_ylim(0, 120)
    ax.set_aspect("equal")
    ax.axis("off")
    fig.patch.set_facecolor(BG_COLOR)
    ax.set_title(
        "EPC (Event-driven Process Chain) \u2014 Obs\u0142uga reklamacji",
        fontsize=TITLE_SIZE,
        fontweight="bold",
        pad=12,
    )

    cx = 50
    y = 114
    step = 9.5

    def draw_epc_event(x, y, text) -> None:
        """Draw epc event."""
        w, h = 26, 5.5
        rect = FancyBboxPatch(
            (x - w / 2, y - h / 2),
            w,
            h,
            boxstyle="round,pad=0.5",
            lw=1.5,
            edgecolor=LINE_COLOR,
            facecolor="#D8D8D8",
        )
        ax.add_patch(rect)
        ax.text(x, y, text, ha="center", va="center", fontsize=8)

    def draw_epc_function(x, y, text) -> None:
        """Draw epc function."""
        w, h = 26, 5.5
        rect = FancyBboxPatch(
            (x - w / 2, y - h / 2),
            w,
            h,
            boxstyle="round,pad=0.3",
            lw=2,
            edgecolor=LINE_COLOR,
            facecolor="white",
        )
        ax.add_patch(rect)
        ax.text(x, y, text, ha="center", va="center", fontsize=8, fontweight="bold")

    def draw_epc_connector(x, y, text) -> None:
        """Draw epc connector."""
        c = plt.Circle((x, y), 2.8, lw=1.5, edgecolor=LINE_COLOR, facecolor="white")
        ax.add_patch(c)
        ax.text(x, y, text, ha="center", va="center", fontsize=9, fontweight="bold")

    # E1
    draw_epc_event(cx, y, "Reklamacja wp\u0142yn\u0119\u0142a")

    # F1
    y -= step
    draw_epc_function(cx, y, "Przyjmij zg\u0142oszenie")
    draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)

    # E2
    y -= step
    draw_epc_event(cx, y, "Zg\u0142oszenie przyj\u0119te")
    draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)

    # F2
    y -= step
    draw_epc_function(cx, y, "Zweryfikuj zasadno\u015b\u0107")
    draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)

    # E3
    y -= step
    draw_epc_event(cx, y, "Zasadno\u015b\u0107 oceniona")
    draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)

    # XOR split
    y -= step
    draw_epc_connector(cx, y, "XOR")
    draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)
    split_y = y

    left_x = cx - 28
    right_x = cx + 28

    # Left branch
    by = split_y - step
    draw_epc_event(left_x, by, "Reklamacja zasadna")
    draw_line(ax, cx - 2.8, split_y, left_x, split_y)
    draw_arrow(ax, left_x, split_y, left_x, by + 2.8)

    by2 = by - step
    draw_epc_function(left_x, by2, "Przygotuj wymian\u0119/zwrot")
    draw_arrow(ax, left_x, by - 2.8, left_x, by2 + 2.8)

    by3 = by2 - step
    draw_epc_event(left_x, by3, "Wymiana przygotowana")
    draw_arrow(ax, left_x, by2 - 2.8, left_x, by3 + 2.8)

    # Right branch
    draw_epc_event(right_x, by, "Reklamacja niezasadna")
    draw_line(ax, cx + 2.8, split_y, right_x, split_y)
    draw_arrow(ax, right_x, split_y, right_x, by + 2.8)

    draw_epc_function(right_x, by2, "Odrzu\u0107 reklamacj\u0119")
    draw_arrow(ax, right_x, by - 2.8, right_x, by2 + 2.8)

    draw_epc_event(right_x, by3, "Reklamacja odrzucona")
    draw_arrow(ax, right_x, by2 - 2.8, right_x, by3 + 2.8)

    # XOR merge
    merge_y = by3 - step
    draw_epc_connector(cx, merge_y, "XOR")
    draw_line(ax, left_x, by3 - 2.8, left_x, merge_y)
    draw_line(ax, left_x, merge_y, cx - 2.8, merge_y)
    draw_line(ax, right_x, by3 - 2.8, right_x, merge_y)
    draw_line(ax, right_x, merge_y, cx + 2.8, merge_y)

    # F: Powiadom
    y = merge_y - step
    draw_epc_function(cx, y, "Powiadom klienta")
    draw_arrow(ax, cx, merge_y - 2.8, cx, y + 2.8)

    # E: Klient powiadomiony
    y -= step
    draw_epc_event(cx, y, "Klient powiadomiony")
    draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)

    # Legend
    ly = 3
    draw_epc_event(16, ly, "Zdarzenie")
    draw_epc_function(46, ly, "Funkcja")
    draw_epc_connector(68, ly, "XOR")
    ax.text(72, ly, "= \u0141\u0105cznik logiczny", fontsize=7, va="center")

    fig.tight_layout()
    fig.savefig(
        str(Path(OUTPUT_DIR) / "epc_reklamacja.png"),
        dpi=DPI,
        facecolor="white",
        bbox_inches="tight",
    )
    plt.close(fig)
    print("  OK EPC saved")


# =========================================================================
# 4. Classic Flowchart
# =========================================================================
def generate_flowchart() -> None:
    """Generate flowchart."""
    fig, ax = plt.subplots(figsize=(8.27, 11))
    ax.set_xlim(0, 100)
    ax.set_ylim(0, 110)
    ax.set_aspect("equal")
    ax.axis("off")
    fig.patch.set_facecolor(BG_COLOR)
    ax.set_title(
        "Schemat blokowy (Flowchart) \u2014 Obs\u0142uga reklamacji",
        fontsize=TITLE_SIZE,
        fontweight="bold",
        pad=12,
    )

    cx = 50
    y = 103
    step = 11

    def draw_terminal(x, y, text) -> None:
        """Draw terminal."""
        w, h = 20, 5.5
        rect = FancyBboxPatch(
            (x - w / 2, y - h / 2),
            w,
            h,
            boxstyle="round,pad=1.0",
            lw=2,
            edgecolor=LINE_COLOR,
            facecolor="#E0E0E0",
        )
        ax.add_patch(rect)
        ax.text(
            x, y, text, ha="center", va="center", fontsize=FONT_SIZE, fontweight="bold"
        )

    def draw_process_box(x, y, text) -> None:
        """Draw process box."""
        w, h = 26, 6
        rect = plt.Rectangle(
            (x - w / 2, y - h / 2),
            w,
            h,
            lw=1.5,
            edgecolor=LINE_COLOR,
            facecolor="white",
        )
        ax.add_patch(rect)
        ax.text(x, y, text, ha="center", va="center", fontsize=FONT_SIZE)

    def draw_io_shape(x, y, text) -> None:
        """Draw io shape."""
        w, h = 26, 5.5
        skew = 3
        verts = [
            (x - w / 2 + skew, y + h / 2),
            (x + w / 2 + skew, y + h / 2),
            (x + w / 2 - skew, y - h / 2),
            (x - w / 2 - skew, y - h / 2),
            (x - w / 2 + skew, y + h / 2),
        ]
        codes = [
            MplPath.MOVETO,
            MplPath.LINETO,
            MplPath.LINETO,
            MplPath.LINETO,
            MplPath.CLOSEPOLY,
        ]
        patch = mpatches.PathPatch(
            MplPath(verts, codes), facecolor="white", edgecolor=LINE_COLOR, lw=1.5
        )
        ax.add_patch(patch)
        ax.text(x, y, text, ha="center", va="center", fontsize=FONT_SIZE)

    # Start
    draw_terminal(cx, y, "START")

    # I/O
    y -= step
    draw_io_shape(cx, y, "Reklamacja od klienta")
    draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)

    # Process
    y -= step
    draw_process_box(cx, y, "Przyjmij zg\u0142oszenie")
    draw_arrow(ax, cx, y + step - 2.8, cx, y + 3)

    # Process
    y -= step
    draw_process_box(cx, y, "Zweryfikuj zasadno\u015b\u0107")
    draw_arrow(ax, cx, y + step - 3, cx, y + 3)

    # Decision
    y -= step
    draw_diamond(ax, cx, y, 4.5, "Zasadna?")
    draw_arrow(ax, cx, y + step - 3, cx, y + 4.5)
    dec_y = y

    # Left: Tak
    left_x = cx - 26
    draw_process_box(left_x, dec_y, "Przygotuj wymian\u0119/zwrot")
    draw_line(ax, cx - 4.5, dec_y, left_x + 13, dec_y)
    ax.text(cx - 7, dec_y + 2, "Tak", fontsize=8, ha="center", fontweight="bold")

    # Right: Nie
    right_x = cx + 26
    draw_process_box(right_x, dec_y, "Odrzu\u0107 reklamacj\u0119")
    draw_line(ax, cx + 4.5, dec_y, right_x - 13, dec_y)
    ax.text(cx + 7, dec_y + 2, "Nie", fontsize=8, ha="center", fontweight="bold")

    # Merge
    merge_y = dec_y - step
    draw_line(ax, left_x, dec_y - 3, left_x, merge_y)
    draw_line(ax, right_x, dec_y - 3, right_x, merge_y)
    draw_line(ax, left_x, merge_y, right_x, merge_y)
    ax.plot(cx, merge_y, "ko", markersize=4)

    # Process: Powiadom
    y = merge_y - step + 3
    draw_process_box(cx, y, "Powiadom klienta")
    draw_arrow(ax, cx, merge_y, cx, y + 3)

    # I/O
    y -= step
    draw_io_shape(cx, y, "Odpowied\u017a do klienta")
    draw_arrow(ax, cx, y + step - 3, cx, y + 2.8)

    # End
    y -= step
    draw_terminal(cx, y, "KONIEC")
    draw_arrow(ax, cx, y + step - 2.8, cx, y + 2.8)

    # Legend
    ly = 4
    ax.text(5, ly, "Legenda:", fontsize=7, fontweight="bold", va="center")
    draw_terminal(18, ly, "")
    ax.text(18, ly, "Start/\nKoniec", fontsize=5.5, ha="center", va="center")
    w, h = 9, 3
    ax.add_patch(
        plt.Rectangle(
            (32 - w / 2, ly - h / 2),
            w,
            h,
            lw=1.5,
            edgecolor=LINE_COLOR,
            facecolor="white",
        )
    )
    ax.text(32, ly, "Proces", fontsize=6, ha="center", va="center")
    draw_diamond(ax, 46, ly, 2)
    ax.text(49.5, ly, "= Decyzja", fontsize=6, va="center")
    skew = 1.5
    w2, h2 = 9, 3
    verts = [
        (62 - w2 / 2 + skew, ly + h2 / 2),
        (62 + w2 / 2 + skew, ly + h2 / 2),
        (62 + w2 / 2 - skew, ly - h2 / 2),
        (62 - w2 / 2 - skew, ly - h2 / 2),
        (62 - w2 / 2 + skew, ly + h2 / 2),
    ]
    codes = [
        MplPath.MOVETO,
        MplPath.LINETO,
        MplPath.LINETO,
        MplPath.LINETO,
        MplPath.CLOSEPOLY,
    ]
    ax.add_patch(
        mpatches.PathPatch(
            MplPath(verts, codes), facecolor="white", edgecolor=LINE_COLOR, lw=1.2
        )
    )
    ax.text(62, ly, "We/Wy", fontsize=6, ha="center", va="center")

    fig.tight_layout()
    fig.savefig(
        str(Path(OUTPUT_DIR) / "flowchart_reklamacja.png"),
        dpi=DPI,
        facecolor="white",
        bbox_inches="tight",
    )
    plt.close(fig)
    print("  OK Flowchart saved")


# =========================================================================
if __name__ == "__main__":
    print(f"Generating diagrams to {OUTPUT_DIR}/...")
    generate_bpmn()
    generate_uml_activity()
    generate_epc()
    generate_flowchart()
    print(f"\nAll 4 diagrams saved to {OUTPUT_DIR}/")
    for f in sorted([p.name for p in Path(OUTPUT_DIR).iterdir()]):
        if f.endswith(".png"):
            size_kb = Path(str(Path(OUTPUT_DIR).stat().st_size / f)) / 1024
            print(f"  {f} ({size_kb:.0f} KB)")
