import cairosvg,math
W,H=1600,900
def txt(x,y,s,size=16,anchor="middle",weight="normal",fill="#111"):
    return f'<text x="{x}" y="{y}" font-family="Arial,Helvetica,sans-serif" font-size="{size}" text-anchor="{anchor}" font-weight="{weight}" fill="{fill}">{s}</text>'
def leader(x1,y1,x2,y2):
    return f'<line x1="{x1}" y1="{y1}" x2="{x2}" y2="{y2}" stroke="#333" stroke-width="1.5"/><circle cx="{x2}" cy="{y2}" r="3" fill="#333"/>'
def vagues(x,y,w,n,col="#a8c4dc"):
    return "".join(f'<path d="M {x+i*w/n} {y} q {w/n/4} -6 {w/n/2} 0 q {w/n/4} 6 {w/n/2} 0" stroke="{col}" stroke-width="2" fill="none"/>' for i in range(n))
def eolienne(x,y,h,r):
    s=[f'<rect x="{x-2}" y="{y}" width="4" height="{h}" fill="#444"/>',f'<circle cx="{x}" cy="{y}" r="3" fill="#333"/>']
    for a in (0,120,240):
        ax=x+r*math.sin(math.radians(a));ay=y-r*math.cos(math.radians(a))
        s.append(f'<line x1="{x}" y1="{y}" x2="{ax:.0f}" y2="{ay:.0f}" stroke="#333" stroke-width="2.5"/>')
    return "".join(s)
def dessin(taille):
    s=[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="#eef3f7"/>']
    mer=(taille==3)
    s.append('<polygon points="0,700 480,700 700,260 900,180 1150,120 1600,100 1600,830 0,830" fill="#a89a7c"/>')
    s.append('<polygon points="900,180 1150,120 1600,100 1600,140 1160,160 910,215" fill="#7f9a6a"/>')
    s.append('<polygon points="480,700 700,260 735,262 520,700" fill="#8c7b5c"/>')
    if mer:
        s.append('<rect x="0" y="700" width="480" height="130" fill="#3b7fb5"/>')
        s.append(vagues(10,720,460,10,"#9fc3e0"))
        s.append(txt(240,790,"La mer : bassin bas de la boucle salée, et jamais un village sous le lac",13,"middle","bold","#fff"))
    else:
        s.append('<polygon points="0,700 480,700 520,700 520,730 0,730" fill="#b5c49f"/>')
    s.append('<rect x="0" y="830" width="1600" height="70" fill="#17415f"/>')
    for i in range(12):
        x=960+i*50
        s.append(f'<line x1="{x}" y1="{145-i*2}" x2="{x+8}" y2="{125-i*2}" stroke="#2f6fb5" stroke-width="2" stroke-dasharray="3,3"/>')
    s.append('<path d="M 930 178 L 1590 108" stroke="#2c7fb8" stroke-width="5" fill="none"/>')
    s.append(txt(1260,80,"L'impluvium Pacha : la montagne reliée au lac par un canal de ceinture de 20 à 45 km",14,"middle","bold"))
    s.append(txt(1260,98,"7 km² captés par kilomètre, 0,5 M€ le kilomètre, remboursé en un à deux ans : le levier qui fait baisser le kWh",12,"middle"))
    s.append('<ellipse cx="1080" cy="235" rx="150" ry="38" fill="#1b4f7a" stroke="#0a3d62" stroke-width="2"/>')
    s.append(vagues(950,235,260,8))
    s.append('<rect x="925" y="222" width="12" height="40" fill="#8a6a3e"/>')
    s.append(txt(1210,300,"Bassin 3 : le lac de pluie, 5 à 15 fois le bassin haut",14,"middle","bold"))
    s.append(txt(1210,318,{1:"2 millions de m³ (3 en mousson), digue en argile compactée, décantation",2:"8 millions de m³ (12 en mousson), digue en argile compactée, décantation",3:"4 millions de m³ d'eau douce (12 en mousson), au-dessus de la mer, pas d'un village"}[taille],12,"middle"))
    s.append('<rect x="1400" y="215" width="180" height="40" fill="#c9b99a" stroke="#8a6a3e"/>')
    for i in range(9):
        s.append(f'<line x1="{1405+i*20}" y1="217" x2="{1415+i*20}" y2="253" stroke="#8a6a3e" stroke-width="1"/>')
    s.append(txt(1490,272,"Impluvium construit : argile et gravier,",11,"middle"))
    s.append(txt(1490,287,"0,2 km² en option, garantie d'eau",11,"middle"))
    s.append('<path d="M 940 262 L 940 330 L 860 330" stroke="#5b8fb5" stroke-width="5" fill="none"/>')
    s.append('<rect x="730" y="330" width="130" height="18" rx="4" fill="#8a6a3e"/>')
    s.append(txt(722,318,"Le lac remplit le bassin haut en premier,",11,"end"))
    s.append(txt(722,333,"les pompes complètent",11,"end"))
    if taille==3:
        s.append('<rect x="600" y="350" width="230" height="45" fill="#1b4f7a" stroke="#0a3d62" stroke-width="2"/>')
        s.append('<rect x="713" y="350" width="4" height="45" fill="#d8cdb4"/>')
        s.append(vagues(605,372,105,3));s.append(vagues(720,372,105,3,"#c8e0b0"))
        s.append(txt(845,378,"Bassin haut en deux cellules, 2 × 400 000 m³ : douce (pluie) et salée (boucle de mer)",12,"start","bold"))
    else:
        s.append('<rect x="600" y="350" width="230" height="45" fill="#1b4f7a" stroke="#0a3d62" stroke-width="2"/>')
        s.append(vagues(605,372,220,6))
        s.append(txt(845,378,{1:"Bassin haut 200 000 m³, revêtu, marnage quotidien",2:"Bassin haut 800 000 m³, revêtu, marnage quotidien"}[taille],12,"start","bold"))
    for i in range(4 if taille==1 else 8):
        x=1200+i*(60 if taille==1 else 45)
        s.append(eolienne(x,132-i*3,50,18))
    s.append(txt(1240,440,{1:"10 éoliennes de 6 MW et 16 MWc de trackers : la V11 fait le kWh",2:"40 éoliennes de 6 MW, mâts de 150 m, 16 MWc : la V14 fait le kWh",3:"10 éoliennes, 100 MWc et 1 000 panneaux hybrides : la V15 complète"}[taille],13,"middle","bold"))
    s.append(txt(1240,458,"Quand le lac a de l'eau, les pompes dorment et tout le vent se vend en direct",12,"middle"))
    s.append('<path d="M 640 395 L 520 700 L 440 700" stroke="#7fb3d9" stroke-width="9" fill="none"/>')
    s.append('<path d="M 640 395 L 520 700 L 440 700" stroke="#2c3e50" stroke-width="3" fill="none"/>')
    s.append(txt(640,662,{1:"Conduite 300 m, Pelton 12 MW, pompes 16 MW, Pelton de pluie 4,3 MW",2:"Deux DN2000, 300 m, Pelton 48 MW, pompes 64 MW, Pelton de pluie 2 × 4,5 MW à 45 km de canal",3:"Puits blindé 1 500 m, Pelton 300 MW en duplex : 180 MW hors pointe sur la pluie"}[taille],14,"start","bold"))
    s.append(leader(636,657,572,600))
    s.append('<rect x="270" y="645" width="200" height="90" fill="#5a4024"/>')
    s.append('<rect x="315" y="630" width="110" height="20" fill="#8a6a3e"/>')
    s.append(txt(370,675,"Usine",13,"middle","bold","#fff"))
    s.append(txt(370,698,"pointe : grande Pelton, eau du lac d'abord",10,"middle","normal","#fff"))
    s.append(txt(370,716,"jour et nuit : la grande Pelton sur la pluie" if taille==3 else "jour et nuit : Pelton de pluie sur l'excédent",10,"middle","normal","#fff"))
    if taille==3:
        s.append('<rect x="30" y="600" width="250" height="40" fill="#1b4f7a" stroke="#0a3d62" stroke-width="2"/>')
        s.append(vagues(35,620,240,6,"#c8e0b0"))
        s.append(txt(155,660,"Bassin bas douce : l'eau de la ville, par gravité",12,"middle","bold"))
        s.append('<line x1="300" y1="690" x2="280" y2="620" stroke="#5b8fb5" stroke-width="5"/>')
        s.append('<rect x="40" y="520" width="40" height="60" fill="#c3ccd6" stroke="#9aa6b2"/>')
        s.append('<rect x="100" y="530" width="40" height="50" fill="#c3ccd6" stroke="#9aa6b2"/>')
        s.append(txt(155,495,"La ville côtière : 200 millions de m³",11,"middle","bold"))
        s.append(txt(155,510,"d'eau douce par an, sans dessalement",11,"middle","bold"))
    else:
        s.append('<rect x="40" y="745" width="400" height="55" fill="#1b4f7a" stroke="#0a3d62" stroke-width="2"/>')
        s.append(vagues(45,772,390,10))
        s.append(txt(240,818,{1:"Bassin bas 200 000 m³, berges revêtues",2:"Bassin bas 800 000 m³, berges revêtues"}[taille],13,"middle","bold"))
        s.append('<line x1="300" y1="730" x2="300" y2="745" stroke="#5b8fb5" stroke-width="6"/>')
        s.append('<path d="M 40 772 L 0 772" stroke="#5b8fb5" stroke-width="6"/>')
        s.append(txt(135,650,"Ruisseau régulé vers la vallée :",12,"middle","bold"))
        s.append(txt(135,668,"l'eau de pluie turbinée ressort en bas,",12,"middle"))
        s.append(txt(135,686,"toute l'année, pour les villages et les champs",12,"middle"))
        s.append(leader(120,695,30,765))
    s.append('<g transform="translate(1040,480)">')
    s.append('<rect x="0" y="0" width="520" height="150" fill="#ffffff" stroke="#17415f" stroke-width="2"/>')
    s.append(txt(260,24,{1:"V16 Pacha 1 : base V11, le nombre",2:"V16 Pacha 2 : base V14, les grands versants",3:"V16 Pacha 3 : base V15 côtière, l'eau et la mer"}[taille],15,"middle","bold","#17415f"))
    lignes={1:["Canal de 20 km, 140 km², 1 500 mm : 105 millions de m³ par an","312 GWh au lieu de 226 : 29,4 €/MWh au lieu de 35","Lac de 2 millions de m³, Pelton de pluie 4,3 MW : 22 M€, 131 M€","82 millions de m³ rendus à la vallée par un ruisseau régulé","Va partout où une montagne arrosée domine 5 km de crête"],2:["Canal de 30 km, 210 km², 2 000 mm : 212 millions de m³ par an","1 125 GWh au lieu de 885 : 24 €/MWh au lieu de 28 ; 23,6 à 45 km","Lac de 8 millions de m³ : 40 M€, 404 M€ ; pompes 18 GWh au lieu de 132","196 millions de m³ régulés vers la vallée, crues écrêtées","La centrale la moins chère du site"],3:["Canal de 30 km, 210 km², 2 000 mm : 211 millions de m³ à 1 500 m","251 GWh hors pointe en plus, 212 GWh de surplus non achetés","Lac de 4 millions, bassin bas douce, conduite : 51 M€, 706 M€","200 millions de m³ d'eau douce rendus à la côte, sans dessalement","Jamais au-dessus d'une ville : la mer ou la fosse en bas"]}[taille]
    for i,l in enumerate(lignes):
        s.append(txt(15,52+i*20,l,12,"start","bold" if i==1 else "normal"))
    s.append('</g>')
    titres={1:"Hydroloop Muhleisen 2026 V16 Pacha 1 : la V11 avec son lac de pluie et son canal de ceinture, 312 GWh à 29,4 €/MWh",2:"Hydroloop Muhleisen 2026 V16 Pacha 2 : la V14 avec son lac de pluie et son canal de ceinture, 1 125 GWh par an à 24 €/MWh",3:"Hydroloop Muhleisen 2026 V16 Pacha 3 : la V15 côtière avec son lac de pluie, la montagne turbinée à 1 500 m et l'eau douce rendue à la côte"}
    s.append(txt(800,860,titres[taille],21,"middle","bold","#fff"))
    s.append(txt(800,885,"Coupe schématique, pas à l'échelle. Pachamama rend l'eau et l'énergie. www.mulo.world, octobre 2026, CC BY 4.0",13,"middle","normal","#dfe7ee"))
    s.append('</svg>')
    return "\n".join(s)
for t in (1,2,3):
    cairosvg.svg2png(bytestring=dessin(t).encode("utf-8"),write_to=f"schema_hydroloop_muhleisen_2026_v16_pacha_{t}.png",output_width=W,output_height=H)
print("ok")
