"""f31_future_map -- concept map of future directions: molecular
simulation, physics-informed machine learning, thermodynamic-consistency
constraints, electrochemical thermodynamics, high-throughput
parameterisation, transferable molecular parameters. Central hub with six
radiating spokes (hexagon layout), centre-out reading order. Pure
schematic (matplotlib primitives only).
"""
import sys
sys.path.insert(0, "/home/claude/eos_lecture/code")
from eosstyle import *
from matplotlib.patches import FancyBboxPatch, FancyArrowPatch

W, H = 12.2, 6.1
YMAX = 1.18
fig, ax = blank(W, H)
ax.set_ylim(0, YMAX)

def box(cx, cy, w, h, text, fc=PAPER, ec=GRAPHITE, tc=INK, fs=10.0, lw=1.2, weight="normal"):
    b = FancyBboxPatch((cx - w/2, cy - h/2), w, h,
                        boxstyle="round,pad=0.012,rounding_size=0.02",
                        linewidth=lw, edgecolor=ec, facecolor=fc, zorder=3)
    ax.add_patch(b)
    ax.text(cx, cy, text, ha="center", va="center", fontsize=fs, color=tc,
             zorder=4, weight=weight, linespacing=1.3)
    return b

def arrow(p0, p1, color=GRAPHITE, lw=1.5):
    a = FancyArrowPatch(p0, p1, arrowstyle="-|>", mutation_scale=12,
                         linewidth=lw, color=color, zorder=2,
                         shrinkA=2, shrinkB=2, connectionstyle="arc3,rad=0.0")
    ax.add_patch(a)

cx, cy = 0.5, 0.53
box(cx, cy, 0.235, 0.135, "Next-generation\nEOS", fc=NAVY, tc="white", fs=13.0, weight="bold")

bw, bh = 0.255, 0.150
spokes = [
    # (x, y, box text, description text, desc side: 'above'/'below'/'left'/'right')
    (0.5,   0.895, "Molecular simulation\n(MD / MC free energy)",
     "benchmark data where\nexperiments are scarce", "above"),
    (0.815, 0.715, "Physics-informed\nmachine learning",
     "learned Helmholtz functions\nwith physical guard rails", "right"),
    (0.815, 0.345, "Thermodynamic\nconsistency constraints",
     "Maxwell relations and limiting\nlaws enforced by construction", "right"),
    (0.5,   0.165, "Electrochemical\nthermodynamics",
     "activity coefficients, solvation,\nvoltage windows", "below"),
    (0.185, 0.345, "High-throughput\nparameterisation",
     "automated fitting across large\nmolecule / parameter sets", "left"),
    (0.185, 0.715, "Transferable molecular\nparameters",
     "group contribution, transfer\nacross homologous series", "left"),
]

hub_edge = {"above": (0, 0.0675), "right": (0.1175, 0.0), "left": (-0.1175, 0.0), "below": (0, -0.0675)}

for sx, sy, txt, desc, side in spokes:
    box(sx, sy, bw, bh, txt, fc=AMBER, ec=GRAPHITE, tc="white", fs=11.2)
    # arrow from hub edge toward box edge (straight line, direction-dependent trim)
    dx, dy = sx - cx, sy - cy
    n = (dx**2 + dy**2) ** 0.5
    ux, uy = dx / n, dy / n
    p0 = (cx + ux * 0.1225, cy + uy * 0.0725)
    p1 = (sx - ux * (bw/2 + 0.012), sy - uy * (bh/2 + 0.012))
    arrow(p0, p1)
    if side == "above":
        ax.text(sx, sy + bh/2 + 0.025, desc, ha="center", va="bottom", fontsize=10.5,
                color=SLATE, linespacing=1.3)
    elif side == "below":
        ax.text(sx, sy - bh/2 - 0.025, desc, ha="center", va="top", fontsize=10.5,
                color=SLATE, linespacing=1.3)
    elif side == "right":
        ax.text(sx + bw/2 + 0.025, sy, desc, ha="left", va="center", fontsize=10.5,
                color=SLATE, linespacing=1.3)
    else:
        ax.text(sx - bw/2 - 0.025, sy, desc, ha="right", va="center", fontsize=10.5,
                color=SLATE, linespacing=1.3)

ax.text(0.5, YMAX - 0.02, "Future directions for the equation of state",
        ha="center", va="top", fontsize=15.5, color=NAVY, weight="bold")

save(fig, "f31_future_map")
