#!/usr/bin/env python3
"""
Daily Curiosity #5 — Чому лід плаває у воді?
Schematic: liquid water (densely packed molecules) vs ice (open hexagonal
lattice with more empty space) → ice is ~9% less dense → floats.
Below — a winter lake cross-section: ice on top, fish in liquid water below.
"""
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch, Circle, FancyBboxPatch, Polygon
import numpy as np

# ---- Canvas ----
fig, ax = plt.subplots(figsize=(12, 7), dpi=160)
ax.set_xlim(0, 12)
ax.set_ylim(0, 7)
ax.set_aspect('equal')
ax.axis('off')

# Cool, icy background
bg = np.linspace(0, 1, 256).reshape(-1, 1)
bg = np.repeat(bg, 256, axis=1)
ax.imshow(
    bg,
    extent=(0, 12, 0, 7),
    cmap=plt.cm.colors.LinearSegmentedColormap.from_list(
        "icy_dark", ["#04111c", "#0a1d33", "#0f2a4a"]
    ),
    aspect='auto',
    zorder=0,
)

# ---- Title and subtitle (Ukrainian) ----
ax.text(
    6, 6.55,
    "Чому лід плаває у воді?",
    ha='center', va='center',
    fontsize=24, fontweight='bold', color='#eaf6ff',
    zorder=10,
)
ax.text(
    6, 6.05,
    "У льоді молекули шикуються в ажурні шестикутники — і займають більше місця, ніж у рідині",
    ha='center', va='center',
    fontsize=11.5, style='italic', color='#bcd9f5',
    zorder=10,
)

# ---- Helper: draw a water molecule (one O + two H) ----
def draw_molecule(cx, cy, scale=0.18, angle=0.0, alpha=1.0, zorder=5):
    a = np.deg2rad(angle)
    # Oxygen
    O = Circle((cx, cy), scale, facecolor='#e84e4e',
               edgecolor='#7a1414', lw=0.8, alpha=alpha, zorder=zorder)
    ax.add_patch(O)
    # Two hydrogens at 104.5°
    h_off = scale * 1.55
    h_ang = np.deg2rad(52.25)  # half of 104.5
    for sign in (-1, 1):
        hx = cx + h_off * np.cos(a + sign * h_ang)
        hy = cy + h_off * np.sin(a + sign * h_ang)
        # Bond
        ax.plot([cx, hx], [cy, hy], color='#cfe5ff',
                lw=0.9 * (1 + 0.4 * (zorder >= 6)), alpha=alpha * 0.85, zorder=zorder)
        # H atom
        H = Circle((hx, hy), scale * 0.55, facecolor='#cfe5ff',
                   edgecolor='#5e7e9e', lw=0.6, alpha=alpha, zorder=zorder + 1)
        ax.add_patch(H)

# ---- LEFT panel: liquid water (densely packed, irregular) ----
panel_left = FancyBboxPatch(
    (0.4, 2.6), 4.6, 2.85,
    boxstyle="round,pad=0.08,rounding_size=0.18",
    fc="#0d2138", ec="#9ec8f0", lw=1.2, zorder=2,
)
ax.add_patch(panel_left)
ax.text(2.7, 5.20, "рідка вода",
        ha='center', va='center', fontsize=13.5, fontweight='bold',
        color='#eaf6ff', zorder=11)
ax.text(2.7, 4.92, "молекули рухаються близько одна до одної",
        ha='center', va='center', fontsize=9.5, style='italic',
        color='#bcd9f5', zorder=11)

# Densely packed (jittered grid) molecules
rng = np.random.default_rng(11)
liquid_positions = []
for ix in range(7):
    for iy in range(4):
        x = 0.85 + ix * 0.62 + rng.uniform(-0.10, 0.10)
        y = 2.95 + iy * 0.45 + rng.uniform(-0.10, 0.10)
        if x < 4.85 and y < 4.65:
            liquid_positions.append((x, y, rng.uniform(-30, 210)))

for (x, y, a) in liquid_positions:
    draw_molecule(x, y, scale=0.13, angle=a, zorder=6)

# Density label
ax.text(2.7, 2.78, "густина ≈ 1000 кг/м³",
        ha='center', va='center', fontsize=10, fontweight='bold',
        color='#9ec8f0', zorder=11)

# ---- RIGHT panel: ice — open hexagonal lattice ----
panel_right = FancyBboxPatch(
    (7.0, 2.6), 4.6, 2.85,
    boxstyle="round,pad=0.08,rounding_size=0.18",
    fc="#0d2138", ec="#a9def0", lw=1.2, zorder=2,
)
ax.add_patch(panel_right)
ax.text(9.3, 5.20, "лід (твердий)",
        ha='center', va='center', fontsize=13.5, fontweight='bold',
        color='#eaf6ff', zorder=11)
ax.text(9.3, 4.92, "шестикутна решітка — між молекулами більше «повітря»",
        ha='center', va='center', fontsize=9.5, style='italic',
        color='#a9def0', zorder=11)

# Hex lattice positions (centers) inside right panel
# We use a sparse hex grid so that "empty space" is visible
hex_centers = []
hex_dx = 0.9
hex_dy = 0.78
for iy in range(3):
    y = 3.10 + iy * hex_dy
    x_off = 0 if iy % 2 == 0 else hex_dx / 2
    for ix in range(5):
        x = 7.30 + ix * hex_dx + x_off
        if x < 11.40 and y < 4.75:
            hex_centers.append((x, y))

# Draw hex bonds (between nearest neighbors)
for i, (x1, y1) in enumerate(hex_centers):
    for j, (x2, y2) in enumerate(hex_centers):
        if j <= i:
            continue
        d = np.hypot(x1 - x2, y1 - y2)
        if d < hex_dx * 1.05:  # nearest neighbor
            ax.plot([x1, x2], [y1, y2],
                    color='#7fc3e0', lw=1.3, alpha=0.6, zorder=4,
                    linestyle='--')

# Draw molecules at hex positions
for (x, y) in hex_centers:
    draw_molecule(x, y, scale=0.13, angle=rng.uniform(-30, 210), zorder=6)

# Density label
ax.text(9.3, 2.78, "густина ≈ 917 кг/м³  (на ~9% менша)",
        ha='center', va='center', fontsize=10, fontweight='bold',
        color='#a9def0', zorder=11)

# ---- Arrow between the two panels with caption ----
arr = FancyArrowPatch(
    (5.05, 3.95), (6.95, 3.95),
    arrowstyle='-|>', mutation_scale=22,
    color='#eaf6ff', lw=2.2, zorder=7,
)
ax.add_patch(arr)
ax.text(6.0, 4.30, "замерзає\n(0 °C)",
        ha='center', va='center', fontsize=10, fontweight='bold',
        color='#eaf6ff', zorder=11)
ax.text(6.0, 3.55, "об'єм ↑\nгустина ↓",
        ha='center', va='center', fontsize=9.5, style='italic',
        color='#9ec8f0', zorder=11)

# ---- BOTTOM section: lake cross-section ----
# Water body (deep blue)
water_body = Polygon(
    [(0.5, 0.25), (11.5, 0.25), (11.5, 2.10), (0.5, 2.10)],
    facecolor='#0e3a64', edgecolor='#1a5a92', lw=1.0, zorder=2,
)
ax.add_patch(water_body)

# Ice layer on top (a sheet with a slightly jagged top)
ice_top_y = 2.05
ice_pts = [(0.5, 1.65)]
xs = np.linspace(0.5, 11.5, 60)
for x in xs:
    bump = 0.08 * np.sin(x * 1.7) + 0.04 * np.sin(x * 4.3)
    ice_pts.append((x, ice_top_y + bump))
ice_pts.append((11.5, 1.65))
ice = Polygon(ice_pts, facecolor='#dff1ff', edgecolor='#9ec8f0',
              lw=1.0, zorder=3, alpha=0.92)
ax.add_patch(ice)

ax.text(6.0, 1.85, "лід (плаває зверху)",
        ha='center', va='center', fontsize=10.5, fontweight='bold',
        color='#1a3a5a', zorder=11)

# Fish silhouettes below
def draw_fish(cx, cy, size=0.22, color='#a9def0', flip=False):
    # Body — ellipse-ish polygon
    s = -1 if flip else 1
    body = Polygon(
        [(cx - s * size * 1.3, cy),
         (cx - s * size * 0.5, cy + size * 0.5),
         (cx + s * size * 0.7, cy + size * 0.4),
         (cx + s * size * 1.0, cy),
         (cx + s * size * 0.7, cy - size * 0.4),
         (cx - s * size * 0.5, cy - size * 0.5)],
        closed=True, facecolor=color, edgecolor='#3a6a8a', lw=0.8, zorder=5,
    )
    ax.add_patch(body)
    # Tail
    tail = Polygon(
        [(cx - s * size * 1.3, cy),
         (cx - s * size * 1.7, cy + size * 0.5),
         (cx - s * size * 1.7, cy - size * 0.5)],
        closed=True, facecolor=color, edgecolor='#3a6a8a', lw=0.8, zorder=5,
    )
    ax.add_patch(tail)
    # Eye
    ax.plot([cx + s * size * 0.65], [cy + size * 0.12],
            'o', color='#04111c', markersize=2.2, zorder=6)

draw_fish(2.5, 1.10, size=0.20, color='#ffd86b', flip=False)
draw_fish(5.7, 0.85, size=0.18, color='#a9def0', flip=True)
draw_fish(8.6, 1.20, size=0.22, color='#ff9b6b', flip=False)
draw_fish(10.2, 0.65, size=0.16, color='#cfe5ff', flip=True)

# Liquid-water label
ax.text(6.0, 0.45, "рідка вода (+4 °C на дні — найгустіша)",
        ha='center', va='center', fontsize=9.5, style='italic',
        color='#cfe5ff', zorder=11)

# Subtle horizontal "thermocline" line near top of liquid water
ax.plot([0.5, 11.5], [1.55, 1.55], color='#9ec8f0',
        lw=0.7, linestyle=':', alpha=0.6, zorder=4)

# Bottom note about life on Earth
ax.text(6.0, 0.05,
        "якби лід тонув — водойми промерзали б до дна, і риби, і життя зникли б",
        ha='center', va='center', fontsize=9.5, fontweight='bold',
        color='#ffd86b', zorder=11)

plt.tight_layout()
out = "/sessions/gifted-sharp-dijkstra/mnt/daily-curiosity/daily-curiosity-05.png"
plt.savefig(out, dpi=160, facecolor='#04111c', bbox_inches='tight', pad_inches=0.15)
print(f"Saved: {out}")
