"""Generative artwork for each experience type: Moroccan night scenes in navy, plum and gold (600x600 SVG -> WebP)."""
import math, random, os, asyncio
OUT = os.path.dirname(os.path.abspath(__file__))
W = 600

def defs(sky, extra=""):
    a, b, c = sky
    return f'''<defs>
<linearGradient id="sky" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="{a}"/><stop offset=".62" stop-color="{b}"/><stop offset="1" stop-color="{c}"/></linearGradient>
<linearGradient id="gold" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#F6E3A1"/><stop offset=".5" stop-color="#D9B44A"/><stop offset="1" stop-color="#9A7444"/></linearGradient>
<radialGradient id="glow" cx=".5" cy=".5" r=".5"><stop offset="0" stop-color="#FFE7B0" stop-opacity=".9"/><stop offset=".35" stop-color="#E6B866" stop-opacity=".35"/><stop offset="1" stop-color="#E6B866" stop-opacity="0"/></radialGradient>
<radialGradient id="vig" cx=".5" cy=".45" r=".75"><stop offset=".55" stop-color="#000" stop-opacity="0"/><stop offset="1" stop-color="#05040A" stop-opacity=".7"/></radialGradient>
<filter id="grain"><feTurbulence type="fractalNoise" baseFrequency=".9" numOctaves="2" stitchTiles="stitch"/><feColorMatrix values="0 0 0 0 1  0 0 0 0 .95  0 0 0 0 .85  0 0 0 .08 0"/></filter>
<filter id="soft"><feGaussianBlur stdDeviation="6"/></filter>
{extra}</defs>'''

def stars(n, seed, ymax=330):
    r = random.Random(seed); s = ""
    for _ in range(n):
        x, y, rr = r.uniform(0, W), r.uniform(0, ymax), r.choice([.6, .8, 1, 1.3, 1.8])
        s += f'<circle cx="{x:.1f}" cy="{y:.1f}" r="{rr}" fill="#FFF3D6" opacity="{r.uniform(.35, .95):.2f}"/>'
    return s

def finish(body, sky, extra=""):
    return f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {W} {W}" width="{W}" height="{W}">{defs(sky, extra)}<rect width="{W}" height="{W}" fill="url(#sky)"/>{body}<rect width="{W}" height="{W}" fill="url(#vig)"/><rect width="{W}" height="{W}" filter="url(#grain)"/></svg>'

def dunes(base, colors, seed):
    r = random.Random(seed); s = ""
    for i, col in enumerate(colors):
        y = base + i * 46
        pts = [f"M0 {y + r.uniform(-20, 20):.0f}"]
        for x in range(0, W + 150, 150):
            pts.append(f"Q{x + 75} {y + r.uniform(-60, 30):.0f} {x + 150} {y + r.uniform(-18, 18):.0f}")
        s += f'<path d="{" ".join(pts)} L{W} {W} L0 {W}Z" fill="{col}"/>'
    return s

def moon(x, y, r=34):
    return f'<circle cx="{x}" cy="{y}" r="{r*3.2}" fill="url(#glow)" opacity=".55"/><circle cx="{x}" cy="{y}" r="{r}" fill="url(#gold)"/><circle cx="{x+r*.42}" cy="{y-r*.22}" r="{r*.92}" fill="#1A1430"/>'

def sun(x, y, r=46, op=1):
    return f'<circle cx="{x}" cy="{y}" r="{r*3.4}" fill="url(#glow)" opacity="{op*.9}"/><circle cx="{x}" cy="{y}" r="{r}" fill="url(#gold)" opacity="{op}"/>'

def mountains(base, cols, seed, peaks=5, h=170, snow=False):
    r = random.Random(seed); s = ""
    for i, col in enumerate(cols):
        y = base + i * 40; pts = [f"M0 {y}"]; x = 0
        while x < W:
            px = x + r.uniform(60, 140); py = y - r.uniform(h * .45, h) / (1 + i * .35)
            pts.append(f"L{px:.0f} {py:.0f}")
            if snow and i == 0: s_cap = (px, py)
            x = px + r.uniform(50, 120); pts.append(f"L{x:.0f} {y - r.uniform(5, 30):.0f}")
        s += f'<path d="{" ".join(pts)} L{W} {W} L0 {W}Z" fill="{col}"/>'
    return s

def arch(cx, top, w, h, fill, stroke="none", sw=0):
    # Moroccan horseshoe arch
    r = w / 2
    return f'<path d="M{cx-r} {top+h} L{cx-r} {top+r*1.05} A{r*1.08} {r*1.08} 0 1 1 {cx+r} {top+r*1.05} L{cx+r} {top+h}Z" fill="{fill}" stroke="{stroke}" stroke-width="{sw}"/>'

def lantern(x, y, s=1, op=1):
    return f'''<g transform="translate({x} {y}) scale({s})" opacity="{op}"><line x1="0" y1="-120" x2="0" y2="-34" stroke="#C9A27A" stroke-width="1.6"/>
<circle cx="0" cy="0" r="70" fill="url(#glow)" opacity=".75"/>
<path d="M-6 -34h12l4 8h-20z" fill="url(#gold)"/><path d="M-20 -24h40l-6 46h-28z" fill="#F2C26B" opacity=".9"/>
<path d="M-20 -24h40l-6 46h-28z" fill="none" stroke="#9A7444" stroke-width="2"/><path d="M-10 -24v46M0 -24v46M10 -24v46" stroke="#9A7444" stroke-width="1.4" opacity=".8"/>
<path d="M-14 22h28l-6 8h-16z" fill="url(#gold)"/></g>'''

def star8(cx, cy, r, fill, op=1, rot=0):
    pts = []
    for i in range(16):
        a = math.radians(i * 22.5 + rot); rr = r if i % 2 == 0 else r * .62
        pts.append(f"{cx + rr*math.cos(a):.1f},{cy + rr*math.sin(a):.1f}")
    return f'<polygon points="{" ".join(pts)}" fill="{fill}" opacity="{op}"/>'

NIGHT = ("#0B0A1F", "#2A1838", "#5B2E3C")
DUSK = ("#141331", "#4A2340", "#C66B4E")
SUNRISE = ("#1B1E3E", "#7A4258", "#F0A86A")
TEAL = ("#061A1F", "#0D3A3E", "#1E5A55")

S = {}
S["desert"] = finish(stars(110, 1) + moon(440, 120) + dunes(360, ["#6E3F2B", "#8C5233", "#A8683C", "#C2844A"], 3) +
    "".join(f'<g transform="translate({x} {y})"><path d="M-26 0 L0 -34 L26 0Z" fill="#2B1A1A"/><path d="M-6 0 L0 -12 L6 0Z" fill="#FFCF7A"/><circle cx="0" cy="-6" r="22" fill="url(#glow)" opacity=".7"/></g>' for x, y in [(150, 420), (205, 430), (262, 424)]), NIGHT)
S["sea"] = finish(stars(40, 2, 200) + sun(300, 300, 50) +
    '<rect y="300" width="600" height="300" fill="#13213A"/>' +
    "".join(f'<rect x="{300 - w/2}" y="{y}" width="{w}" height="3" rx="1.5" fill="#F6D58A" opacity="{op}"/>' for w, y, op in [(120, 312, .9), (180, 330, .7), (90, 348, .8), (220, 370, .5), (140, 395, .6), (260, 425, .35), (180, 460, .3), (300, 500, .2)]) +
    '<path d="M0 300 L0 250 L40 250 L40 238 L60 238 L60 250 L110 250 L110 232 L128 232 L128 250 L170 250 L180 300Z" fill="#0C0F22"/>' +
    '<path d="M600 300 L600 262 L560 262 L560 244 L540 244 L540 262 L500 262 L490 300Z" fill="#0C0F22"/>' +
    "".join(f'<path d="M{x} {y} q14 -8 28 0 q14 8 28 0" fill="none" stroke="#3B5274" stroke-width="2" opacity=".6"/>' for x, y in [(60, 470), (420, 440), (480, 530), (110, 540), (300, 560)]), DUSK)
S["nature"] = finish(stars(60, 3, 220) + moon(470, 110, 26) + mountains(330, ["#2E3A5C", "#22304A", "#16233A"], 7, h=200) +
    '<path d="M0 470 Q150 430 300 460 T600 450 L600 600 L0 600Z" fill="#0E1A22"/>' +
    "".join(f'<g transform="translate({x} {y})"><path d="M0 0 L0 -60" stroke="#0A1418" stroke-width="5"/>' + "".join(f'<path d="M0 -60 q{dx} {dy} {dx*1.6} {dy+18}" fill="none" stroke="#0A1418" stroke-width="6" stroke-linecap="round"/>' for dx, dy in [(-30, -8), (30, -8), (-22, -22), (22, -22), (0, -26)]) + '</g>' for x, y in [(110, 520), (480, 510)]), NIGHT)
S["culture"] = finish(stars(70, 4, 260) + moon(300, 150, 30) +
    '<rect x="390" y="190" width="56" height="240" fill="#1B1430"/><rect x="398" y="170" width="40" height="22" fill="#1B1430"/><path d="M410 170 L418 140 L426 170Z" fill="url(#gold)"/>' +
    "".join(f'<rect x="{x}" y="{y}" width="10" height="16" rx="5" fill="#E9B95E" opacity=".85"/>' for x, y in [(405, 215), (421, 215), (413, 270), (413, 330)]) +
    '<path d="M0 430 L600 430 L600 600 L0 600Z" fill="#120E22"/>' +
    '<path d="M0 0 H600 V600 H0Z M120 600 L120 250 A180 180 0 1 1 480 250 L480 600Z" fill="#0A0814" fill-rule="evenodd" opacity=".96"/>' +
    '<path d="M120 600 L120 250 A180 180 0 1 1 480 250 L480 600" fill="none" stroke="url(#gold)" stroke-width="5"/>' +
    '<path d="M136 600 L136 254 A164 164 0 1 1 464 254 L464 600" fill="none" stroke="#9A7444" stroke-width="1.5" opacity=".7"/>' +
    "".join(star8(x, y, 18, "url(#gold)", .55, 0) for x, y in [(50, 80), (550, 80), (50, 520), (550, 520)]), NIGHT)
S["food"] = finish('<circle cx="300" cy="330" r="260" fill="url(#glow)" opacity=".55"/>' +
    '<ellipse cx="300" cy="455" rx="190" ry="34" fill="#3A1A16"/><ellipse cx="300" cy="440" rx="170" ry="30" fill="url(#gold)"/>' +
    '<path d="M150 440 Q300 470 450 440 L432 420 Q300 448 168 420Z" fill="#8C4A2A"/>' +
    '<path d="M180 420 Q300 220 300 168 Q300 220 420 420Z" fill="#B5583A"/><path d="M180 420 Q300 220 300 168 Q300 220 420 420Z" fill="none" stroke="#F2C26B" stroke-width="3"/>' +
    '<path d="M210 380 Q300 360 390 380" stroke="#F2C26B" stroke-width="3" fill="none" opacity=".8"/><path d="M240 320 Q300 305 360 320" stroke="#F2C26B" stroke-width="2.4" fill="none" opacity=".7"/>' +
    '<circle cx="300" cy="160" r="12" fill="url(#gold)"/>' +
    "".join(f'<path d="M{x} 140 q-14 -26 0 -52 q14 -26 0 -52" fill="none" stroke="#F6E3C0" stroke-width="3" stroke-linecap="round" opacity=".35"/>' for x in (270, 300, 330)) +
    "".join(f'<circle cx="{x}" cy="{y}" r="{r}" fill="{c}" opacity=".9"/>' for x, y, r, c in [(90, 470, 8, "#D9622B"), (110, 488, 6, "#E8B04A"), (500, 478, 7, "#8FA43A"), (520, 462, 5, "#D9622B"), (480, 492, 6, "#E8B04A")]),
    ("#1A0E14", "#3B1A1E", "#6A2E25"))
S["crafts"] = finish("".join(star8(75 + (i % 5) * 112.5 + (56 if (i // 5) % 2 else 0), 60 + (i // 5) * 112.5, 46, ["#0E5B4E", "#1E3A6E", "#B5583A", "url(#gold)"][(i + i // 5) % 4], .9, 22.5 * (i % 2)) for i in range(30)) +
    "".join(star8(75 + (i % 5) * 112.5 + (56 if (i // 5) % 2 else 0), 60 + (i // 5) * 112.5, 18, "#0B0A1F", .9) for i in range(30)) +
    '<rect x="150" y="150" width="300" height="300" rx="150" fill="#0B0A1F" opacity=".72"/>' + star8(300, 300, 110, "url(#gold)", 1, 0) + star8(300, 300, 64, "#0B0A1F", 1, 22.5) + star8(300, 300, 34, "#B5583A", 1, 0),
    ("#0B0A1F", "#141331", "#1B1430"))
S["wellness"] = finish('<path d="M120 600 L120 330 Q120 150 300 150 Q480 150 480 330 L480 600Z" fill="#0F3B3C"/>' +
    '<path d="M120 600 L120 330 Q120 150 300 150 Q480 150 480 330 L480 600Z" fill="none" stroke="url(#gold)" stroke-width="4"/>' +
    "".join(f'<circle cx="{x}" cy="{y}" r="7" fill="#FFE7B0" opacity=".9"/><circle cx="{x}" cy="{y}" r="26" fill="url(#glow)" opacity=".6"/>' for x, y in [(300, 200), (250, 220), (350, 220), (215, 255), (385, 255), (275, 245), (325, 245)]) +
    "".join(f'<path d="M{300 + dx} 330 L{300 + dx*3.4} 600" stroke="#FFE7B0" stroke-width="{w}" opacity=".10"/>' for dx, w in [(-40, 40), (0, 50), (40, 40)]) +
    '<path d="M300 380 C270 420 262 446 262 462 a38 38 0 0 0 76 0 c0 -16 -8 -42 -38 -82Z" fill="url(#gold)"/>' +
    "".join(f'<path d="M{x} 560 q-16 -30 0 -60 q16 -30 0 -60" fill="none" stroke="#E6F3EE" stroke-width="5" stroke-linecap="round" opacity=".14"/>' for x in (190, 250, 350, 410)), TEAL)
S["shows"] = finish('<circle cx="300" cy="360" r="300" fill="url(#glow)" opacity=".25"/>' + lantern(300, 300, 1.5) + lantern(150, 230, 1, .9) + lantern(450, 230, 1, .9) + lantern(80, 380, .7, .7) + lantern(520, 380, .7, .7) +
    '<path d="M0 520 Q300 470 600 520 L600 600 L0 600Z" fill="#120A14"/>', ("#120A1E", "#3A1636", "#6A2338"))
S["adventure"] = finish(sun(300, 420, 60, .9) + mountains(470, ["#5A3248", "#3B2440", "#22172E"], 11, h=150) +
    "".join(f'''<g transform="translate({x} {y}) scale({s})"><path d="M0 -60 C-40 -60 -48 -20 -36 6 L-12 40 L12 40 L36 6 C48 -20 40 -60 0 -60Z" fill="{c}"/>
<path d="M0 -60 C-14 -60 -18 -20 -12 6 L-6 40 M0 -60 C14 -60 18 -20 12 6 L6 40" fill="none" stroke="#F6E3A1" stroke-width="2" opacity=".6"/><rect x="-9" y="48" width="18" height="12" rx="2" fill="#2B1A1A"/><path d="M-12 40 L-8 48 M12 40 L8 48" stroke="#2B1A1A" stroke-width="2"/></g>''' for x, y, s, c in [(300, 200, 1.5, "#C0473F"), (140, 150, .8, "#D9A23A"), (470, 120, .9, "#2F6B8C"), (520, 280, .55, "#C0473F")]),
    SUNRISE)
S["daytrip"] = finish(sun(430, 210, 40, .9) + mountains(330, ["#6B3B4A", "#4A2C42"], 13, h=140) +
    '<path d="M0 600 L0 400 Q300 360 600 420 L600 600Z" fill="#2B1C30"/>' +
    '<path d="M330 600 C300 520 260 500 300 460 C330 430 290 410 300 380" fill="none" stroke="url(#gold)" stroke-width="18" stroke-linecap="round"/>' +
    '<path d="M330 600 C300 520 260 500 300 460 C330 430 290 410 300 380" fill="none" stroke="#2B1C30" stroke-width="2" stroke-dasharray="10 12"/>' +
    '<path d="M330 380 L330 330 L350 330 L350 318 L370 318 L370 330 L392 330 L392 380Z" fill="#1C1222"/><rect x="345" y="350" width="8" height="12" rx="4" fill="#F2C26B"/><rect x="368" y="345" width="8" height="12" rx="4" fill="#F2C26B"/>', SUNRISE)
S["local"] = finish("".join(arch(300, 140 + i * 34, 300 - i * 52, 460 - i * 34, ["#2A1838", "#1F1430", "#170F26", "#100A1C", "#0B0716"][i], "url(#gold)", 2.4 - i * .3) for i in range(5)) +
    lantern(300, 300, .9) + "".join(f'<rect x="{x}" y="{y}" width="34" height="56" fill="{c}" opacity=".9"/>' for x, y, c in [(160, 380, "#B5583A"), (200, 396, "#1E5A55"), (366, 386, "#D9A23A"), (406, 400, "#7A2E4A")]), NIGHT)
S["luxury"] = finish(stars(50, 5, 220) + arch(300, 120, 340, 480, "#140E24", "url(#gold)", 4) +
    '<ellipse cx="300" cy="470" rx="120" ry="22" fill="#1E5A55"/><ellipse cx="300" cy="466" rx="104" ry="16" fill="#2F8C7E" opacity=".7"/>' +
    '<path d="M286 470 L292 380 L308 380 L314 470Z" fill="url(#gold)"/><ellipse cx="300" cy="380" rx="44" ry="10" fill="url(#gold)"/><path d="M300 372 q-8 -30 0 -52 q8 22 0 52" fill="#BFE6E0" opacity=".6"/>' +
    "".join(star8(300, 200, 40, "url(#gold)", .9)), ("#0B0A1F", "#221634", "#3B2440"))
S["transfer"] = finish(stars(70, 6, 300) + moon(140, 110, 26) + mountains(340, ["#3B2440", "#2A1E3A"], 17, h=110) + '<path d="M0 380 L600 380 L600 600 L0 600Z" fill="#141226"/>' +
    '<path d="M286 380 L314 380 L560 600 L40 600Z" fill="#24223A"/>' +
    "".join(f'<path d="M{300 - 1.5 - i*2.2} {388 + i*i*4.4} L{300 + 1.5 + i*2.2} {388 + i*i*4.4} L{300 + 2.4 + i*3} {398 + i*i*5.2} L{300 - 2.4 - i*3} {398 + i*i*5.2}Z" fill="url(#gold)"/>' for i in range(9)) +
    '<g transform="translate(300 300)"><circle cx="-34" cy="40" r="70" fill="url(#glow)" opacity=".8"/><circle cx="34" cy="40" r="70" fill="url(#glow)" opacity=".8"/>'
    '<path d="M-70 40 L-58 8 Q-50 -6 -34 -8 L34 -8 Q50 -6 58 8 L70 40 L70 58 L-70 58Z" fill="#0B0A16" stroke="url(#gold)" stroke-width="2.5"/>'
    '<path d="M-48 6 L-40 -2 L40 -2 L48 6Z" fill="#3B5274" opacity=".8"/><circle cx="-46" cy="40" r="8" fill="#FFE7B0"/><circle cx="46" cy="40" r="8" fill="#FFE7B0"/></g>', NIGHT)
S["stay"] = finish(stars(70, 8, 200) + moon(480, 100, 24) + '<rect x="90" y="190" width="420" height="410" fill="#2A1A2E"/>' +
    '<rect x="90" y="182" width="420" height="14" fill="#3B2440"/>' +
    "".join(arch(x, y, 54, 80, "#F2C26B") + f'<circle cx="{x}" cy="{y+40}" r="60" fill="url(#glow)" opacity=".45"/>' for x, y in [(170, 240), (300, 240), (430, 240), (170, 380), (430, 380)]) +
    arch(300, 380, 90, 220, "#120B18", "url(#gold)", 3), NIGHT)
S["package"] = S["luxury"]

async def render():
    from playwright.async_api import async_playwright
    async with async_playwright() as p:
        b = await p.chromium.launch(); pg = await b.new_page(viewport={"width": W, "height": W})
        for k, svg in S.items():
            open(os.path.join(OUT, k + ".svg"), "w").write(svg)
            await pg.set_content(f'<html><body style="margin:0">{svg}</body></html>')
            await pg.screenshot(path=os.path.join(OUT, k + ".png"))
        await b.close()
asyncio.run(render())
from PIL import Image
for k in S:
    Image.open(os.path.join(OUT, k + ".png")).convert("RGB").save(os.path.join(OUT, k + ".webp"), "WEBP", quality=80, method=6)
print("done", len(S))
