#!/usr/bin/env python3
"""Generate abstract technical SVG covers for Brightforge seed content.
Abstract digital geometry only - grid, nodes, dataflow, panels, terminal.
No literal fire/hammer/anvil imagery.
"""
import os

ROOT = os.path.dirname(os.path.abspath(__file__))
UP = os.path.join(os.path.dirname(ROOT), "uploads")

NAVY = "#07111F"
MID  = "#0B1728"
LINE = "#1A2A44"   # grid line
BLUE = "#2563EB"
BLUE2= "#3B82F6"
INK  = "#F8FAFC"   # white text
DIM  = "#7C8BA3"   # dim text
MONO = "ui-monospace, 'JetBrains Mono', 'SF Mono', monospace"
SANS = "Inter, system-ui, -apple-system, sans-serif"

def esc(t):
    return t.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;")

def open_svg(w=1200, h=800):
    return [f'<svg xmlns="http://www.w3.org/2000/svg" width="{w}" height="{h}" viewBox="0 0 {w} {h}">',
            f'<rect width="{w}" height="{h}" fill="{NAVY}"/>']

def grid(s, x0, y0, x1, y1, step=80):
    s.append(f'<g stroke="{LINE}" stroke-width="1">')
    x = x0
    while x <= x1:
        s.append(f'<line x1="{x}" y1="{y0}" x2="{x}" y2="{y1}"/>')
        x += step
    y = y0
    while y <= y1:
        s.append(f'<line x1="{x0}" y1="{y}" x2="{x1}" y2="{y}"/>')
        y += step
    s.append('</g>')

def mono(s, x, y, size, t, fill=DIM, anchor="start", ls="0.14em"):
    s.append(f'<text x="{x}" y="{y}" font-family="{MONO}" font-size="{size}" fill="{fill}" '
             f'letter-spacing="{ls}" text-anchor="{anchor}">{esc(t)}</text>')

def title(s, x, y, t, size=64, fill=INK, w=600):
    s.append(f'<text x="{x}" y="{y}" font-family="{SANS}" font-size="{size}" font-weight="{w}" '
             f'letter-spacing="-0.03em" fill="{fill}">{esc(t)}</text>')

def line(s, x1, y1, x2, y2, color=BLUE, wpx=2, dash=None):
    d = f' stroke-dasharray="{dash}"' if dash else ''
    s.append(f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" stroke="{color}" stroke-width="{wpx}"{d}/>')

def dot(s, x, y, r=5, fill=BLUE):
    s.append(f'<circle cx="{x}" cy="{y}" r="{r}" fill="{fill}"/>')

def cross(s, x, y, r=26, color=BLUE2):
    s.append(f'<g stroke="{color}" stroke-width="1.5" fill="none">')
    s.append(f'<circle cx="{x}" cy="{y}" r="{r}"/>')
    s.append(f'<line x1="{x-r-8}" y1="{y}" x2="{x+r+8}" y2="{y}"/>')
    s.append(f'<line x1="{x}" y1="{y-r-8}" x2="{x}" y2="{y+r+8}"/>')
    s.append('</g>')

def corner_marks(s, x0, y0, x1, y1, n=32):
    s.append(f'<g stroke="{BLUE}" stroke-width="2" fill="none">')
    s.append(f'<path d="M {x0} {y0+n} L {x0} {y0} L {x0+n} {y0}"/>')
    s.append(f'<path d="M {x1-n} {y0} L {x1} {y0} L {x1} {y0+n}"/>')
    s.append(f'<path d="M {x1} {y1-n} L {x1} {y1} L {x1-n} {y1}"/>')
    s.append(f'<path d="M {x0+n} {y1} L {x0} {y1} L {x0} {y1-n}"/>')
    s.append('</g>')

def blueprint(name, sub, tag):
    s = open_svg()
    grid(s, 0, 0, 1200, 800, 80)
    corner_marks(s, 80, 80, 1120, 720)
    cross(s, 600, 320, 60)
    s.append(f'<rect x="80" y="80" width="1040" height="640" fill="none" stroke="{BLUE}" stroke-width="1" opacity="0.35"/>')
    mono(s, 120, 140, 15, tag, BLUE)
    title(s, 120, 620, name, 72)
    mono(s, 122, 670, 17, sub, DIM)
    s.append(f'<rect x="120" y="560" width="64" height="4" fill="{BLUE}"/>')
    s.append('</svg>')
    return "\n".join(s)

def nodes(name, sub, tag, seed=0):
    s = open_svg()
    grid(s, 0, 0, 1200, 800, 120)
    import random
    rnd = random.Random(seed)
    pts = []
    for _ in range(7):
        pts.append((rnd.randint(140, 1060), rnd.randint(150, 560)))
    # connections
    for i in range(len(pts)):
        for j in range(i+1, len(pts)):
            if rnd.random() < 0.35:
                line(s, pts[i][0], pts[i][1], pts[j][0], pts[j][1], BLUE if rnd.random()<0.4 else LINE, 1.5)
    for i, (x, y) in enumerate(pts):
        c = BLUE if i % 3 == 0 else ("#3B82F6" if i % 3 == 1 else LINE)
        dot(s, x, y, 7 if i % 3 else 9, c)
        s.append(f'<circle cx="{x}" cy="{y}" r="13" fill="none" stroke="{c}" stroke-width="1" opacity="0.5"/>')
    mono(s, 120, 140, 15, tag, BLUE)
    title(s, 120, 700, name, 64)
    mono(s, 122, 746, 17, sub, DIM)
    s.append('</svg>')
    return "\n".join(s)

def panels(name, sub, tag):
    s = open_svg()
    grid(s, 0, 0, 1200, 800, 96)
    mono(s, 120, 140, 15, tag, BLUE)
    # floating panels
    p = [
        (620, 180, 430, 220, 0),
        (700, 300, 400, 200, 1),
        (600, 430, 460, 170, 0),
    ]
    for i, (x, y, w, h, lv) in enumerate(p):
        s.append(f'<rect x="{x}" y="{y}" width="{w}" height="{h}" fill="{MID}" stroke="{LINE}" stroke-width="1"/>')
        s.append(f'<rect x="{x}" y="{y}" width="3" height="{h}" fill="{BLUE if i==1 else BLUE2}"/>')
        s.append(f'<line x1="{x+24}" y1="{y+34}" x2="{x+w-24}" y2="{y+34}" stroke="{LINE}" stroke-width="2"/>')
        for k in range(3):
            yy = y + 60 + k * 38
            s.append(f'<rect x="{x+24}" y="{yy}" width="{w-130}" height="10" rx="2" fill="{LINE}"/>')
            s.append(f'<rect x="{x+w-92}" y="{yy}" width="68" height="10" rx="2" fill="{BLUE}" opacity="0.5"/>')
    title(s, 120, 620, name, 64)
    mono(s, 122, 668, 17, sub, DIM)
    s.append(f'<rect x="120" y="560" width="64" height="4" fill="{BLUE}"/>')
    s.append('</svg>')
    return "\n".join(s)

def dataflow(name, sub, tag):
    s = open_svg()
    grid(s, 0, 0, 1200, 800, 100)
    mono(s, 120, 140, 15, tag, BLUE)
    rows = [260, 400, 540]
    for r, y in enumerate(rows):
        x = 120
        line(s, x, y, 1060, y, LINE, 2)
        s.append(f'<path d="M 1060 {y} l 18 -8 M 1060 {y} l 18 8" stroke="{LINE}" stroke-width="2" fill="none"/>')
        xs = 180
        while xs < 1020:
            dot(s, xs, y, 4, BLUE if r % 2 == 0 else BLUE2)
            xs += 84
        dot(s, 120, y, 8, BLUE)
        mono(s, 1040, y + 26, 12, f"STREAM 0{r+1}", DIM, anchor="end")
    title(s, 120, 700, name, 64)
    mono(s, 122, 746, 17, sub, DIM)
    s.append('</svg>')
    return "\n".join(s)

def terminal(name, sub, tag):
    s = open_svg()
    grid(s, 0, 0, 1200, 800, 80)
    mono(s, 120, 140, 15, tag, BLUE)
    # code block
    s.append(f'<rect x="140" y="200" width="760" height="360" fill="{MID}" stroke="{LINE}" stroke-width="1"/>')
    for i in range(3):
        dot(s, 170 + i * 22, 232, 5, BLUE if i == 0 else LINE)
    code = [
        ("$system->register(Order::class);", INK),
        ("$order->status = PickingList::READY;", BLUE2),
        ("$stock->deduct($order->items);", INK),
        ("$notify->dispatch($order);", DIM),
        ("// every step leaves a record", DIM),
    ]
    for i, (txt, c) in enumerate(code):
        mono(s, 170, 300 + i * 44, 19, txt, c, ls="0.02em")
    s.append(f'<rect x="170" y="{300 + len(code)*44}" width="12" height="26" fill="{BLUE}"/>')
    title(s, 120, 680, name, 64)
    mono(s, 122, 726, 17, sub, DIM)
    s.append('</svg>')
    return "\n".join(s)

def connect(name, sub, tag):
    s = open_svg()
    grid(s, 0, 0, 1200, 800, 100)
    mono(s, 120, 140, 15, tag, BLUE)
    for i, (x, w) in enumerate([(200, 260), (740, 260)]):
        s.append(f'<rect x="{x}" y="240" width="{w}" height="220" fill="{MID}" stroke="{LINE}" stroke-width="1"/>')
        s.append(f'<rect x="{x}" y="240" width="3" height="220" fill="{BLUE if i==0 else BLUE2}"/>')
        for k in range(4):
            s.append(f'<rect x="{x+28}" y="{290+k*34}" width="{w-90}" height="9" rx="2" fill="{LINE}"/>')
    # bridge
    for k in range(5):
        y = 280 + k * 36
        line(s, 460, y, 740, y, BLUE if k == 2 else LINE, 2, dash="4 6")
        dot(s, 462, y, 5, BLUE)
    s.append(f'<rect x="470" y="330" width="80" height="26" fill="{BLUE}" opacity="0.9"/>')
    mono(s, 510, 347, 12, "API", NAVY, anchor="middle")
    title(s, 120, 660, name, 64)
    mono(s, 122, 706, 17, sub, DIM)
    s.append('</svg>')
    return "\n".join(s)

def dashboard(name, sub, tag):
    s = open_svg()
    s = open_svg()
    grid(s, 0, 0, 1200, 800, 80)
    mono(s, 120, 140, 15, tag, BLUE)
    # app frame
    s.append(f'<rect x="420" y="170" width="660" height="480" fill="{MID}" stroke="{LINE}" stroke-width="1"/>')
    s.append(f'<rect x="420" y="170" width="132" height="480" fill="#0A1524" stroke="{LINE}" stroke-width="1"/>')
    for k in range(4):
        s.append(f'<rect x="438" y="{200+k*38}" width="96" height="10" rx="2" fill="{BLUE if k==0 else LINE}"/>')
    # KPI chips
    for k in range(3):
        s.append(f'<rect x="574" y="{196+k*56}" width="150" height="42" fill="#0A1524" stroke="{LINE}" stroke-width="1"/>')
        s.append(f'<rect x="590" y="{208+k*56}" width="60" height="8" rx="2" fill="{LINE}"/>')
        s.append(f'<rect x="590" y="{222+k*56}" width="90" height="10" rx="2" fill="{BLUE}"/>')
    # bar chart
    bx = 574
    bw = 26
    for k, hgt in enumerate([70, 120, 90, 150, 110, 160, 95, 130]):
        s.append(f'<rect x="{bx + k*44}" y="{520-hgt}" width="{bw}" height="{hgt}" fill="{BLUE if k%2==0 else BLUE2}" opacity="0.85"/>')
    s.append(f'<line x1="574" y1="520" x2="926" y2="520" stroke="{LINE}" stroke-width="2"/>')
    title(s, 120, 700, name, 60)
    mono(s, 122, 746, 17, sub, DIM)
    s.append('</svg>')
    return "\n".join(s)

def industry(name, idx):
    s = open_svg()
    grid(s, 0, 0, 1200, 800, 80)
    x0 = 100 + (idx % 3) * 60
    corner_marks(s, x0, 120, 1100 - (idx % 2) * 60, 700)
    cross(s, 900 - (idx % 2) * 160, 300 + (idx % 3) * 60, 44)
    s.append(f'<rect x="{x0}" y="120" width="{1100-(idx%2)*60 - x0}" height="580" fill="none" stroke="{BLUE}" stroke-width="1" opacity="0.25"/>')
    mono(s, x0 + 40, 190, 14, f"INDUSTRY / 0{idx+1}", BLUE)
    title(s, x0 + 40, 560, name, 76)
    mono(s, x0 + 42, 618, 16, "PROBLEMS → SOLUTIONS → SYSTEMS", DIM)
    s.append('</svg>')
    return "\n".join(s)

def og_default():
    s = open_svg(1200, 630)
    grid(s, 0, 0, 1200, 630, 60)
    corner_marks(s, 80, 80, 1120, 550, 24)
    mono(s, 110, 190, 16, "PT BRIGHTFORGE TECHNOLOGY SOLUTIONS", BLUE)
    title(s, 110, 420, "Digital Solutions.", 84)
    title(s, 110, 510, "Built For Business.", 84, BLUE2)
    mono(s, 112, 560, 15, "WEBSITES · BUSINESS SYSTEMS · CUSTOM SOFTWARE · AUTOMATION", DIM)
    s.append('</svg>')
    return "\n".join(s)

FILES = {
    "services/web-development.svg":      lambda: blueprint("Web Development", "Websites & web platforms, engineered for purpose.", "SVC / 01"),
    "services/business-systems.svg":     lambda: nodes("Business Systems", "People, process and data — connected.", "SVC / 02", seed=3),
    "services/custom-software.svg":      lambda: terminal("Custom Software", "Engineered around your workflow.", "SVC / 03"),
    "services/automation.svg":           lambda: dataflow("Automation", "Repetitive work, removed by design.", "SVC / 04"),
    "services/system-integration.svg":   lambda: connect("System Integration", "Platforms and APIs, speaking one language.", "SVC / 05"),
    "services/digital-products.svg":     lambda: panels("Digital Products", "From idea to scalable product.", "SVC / 06"),
    "products/brightpos.svg":            lambda: dashboard("BrightPOS", "Retail management, one system.", "PRODUCT / 01"),
    "products/brightstock.svg":          lambda: dataflow("BrightStock", "Multi-location inventory control.", "PRODUCT / 02"),
    "products/brightdesk.svg":           lambda: blueprint("BrightDesk", "Service desk, built into your operation.", "PRODUCT / 03"),
    "portfolio/order-to-delivery.svg":   lambda: dataflow("Order-to-Delivery", "From sales call to signed delivery note.", "CASE / 01"),
    "portfolio/order-to-delivery-2.svg": lambda: terminal("Order Tracking", "Status at every step, no phone calls.", "CASE / 01B"),
    "portfolio/dealer-portal.svg":       lambda: dashboard("Dealer Portal", "One view across the network.", "CASE / 02"),
    "portfolio/admissions-portal.svg":   lambda: blueprint("Admissions Portal", "Registration without the paperwork.", "CASE / 03"),
    "portfolio/document-workflow.svg":   lambda: nodes("Document Workflow", "Approvals with a real audit trail.", "CASE / 04", seed=7),
    "portfolio/integration-layer.svg":   lambda: connect("Integration Layer", "Marketplaces, speaking one language.", "CASE / 05"),
    "articles/off-the-shelf.svg":        lambda: blueprint("Off-the-shelf", "Designed for someone else's business.", "NOTE / 01"),
    "articles/business-system.svg":      lambda: nodes("Business System", "The structure your operation runs on.", "NOTE / 02", seed=11),
    "articles/automation-roi.svg":       lambda: dataflow("Automation ROI", "Payback starts in the boring tasks.", "NOTE / 03"),
    "articles/integration-fails.svg":    lambda: connect("Integration", "Where most projects fail.", "NOTE / 04"),
    "articles/scoping.svg":              lambda: terminal("Scoping", "Outcomes, not feature lists.", "NOTE / 05"),
    "general/industry-retail.svg":       lambda: industry("Retail", 0),
    "general/industry-automotive.svg":   lambda: industry("Automotive", 1),
    "general/industry-distribution.svg": lambda: industry("Distribution", 2),
    "general/industry-education.svg":    lambda: industry("Education", 3),
    "general/industry-corporate.svg":    lambda: industry("Corporate", 4),
    "general/industry-services.svg":     lambda: industry("Services", 5),
    "general/og-default.svg":            og_default,
}

def main():
    for rel, fn in FILES.items():
        path = os.path.join(UP, rel)
        os.makedirs(os.path.dirname(path), exist_ok=True)
        with open(path, "w") as f:
            f.write(fn() + "\n")
        print("wrote", rel)

if __name__ == "__main__":
    main()
