"""
Build the hierarchy schematic v2 — clean color semantics + ordered radial accordion.

Wolf identified two flaws in v1:
  (i) vermilion + blue were used both for biology (A/B compartments, speckles, lamina)
      and for structural-element markers (CTCF anchors, loop arcs, TAD boundary box).
      The reuse blurred which red/blue belongs to which biological role.
  (ii) The lower-panel chromosome-territory schematic placed speckle/lamina dots in
      a roughly random scatter; the radial-accordion structure (interior speckles
      vs peripheral lamina) was not visually obvious.

Fixes:
  - Vermilion (#D55E00) reserved for A-compartment AND speckles ONLY.
  - Blue (#0072B2) reserved for B-compartment AND lamina ONLY.
  - Structural-element markers (CTCF anchors, loop arcs, TAD boundary box,
    nucleosome chain) recoloured to dark grey / black for clean separation.
  - Speckles in the lower panel cluster into ONE compact body in the nuclear
    INTERIOR with a clear "speckles" label.
  - Lamina drawn as a continuous blue band along the inner nuclear envelope.
  - Chromosome wave traces a single contained territory; A-crests touch the
    speckle body, B-troughs touch the lamina band.
  - Lower panel labelled as "ONE chromosome territory" not the whole nucleus.
"""
from __future__ import annotations
import sys, os
from pathlib import Path
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import (FancyBboxPatch, Circle, Rectangle, Arc,
                                FancyArrowPatch, Ellipse, Wedge)

WONG = {'blue':'#0072B2','vermil':'#D55E00','green':'#009E73',
        'gold':'#E69F00','sky':'#56B4E9','pink':'#CC79A7','grey':'#999999',
        'lightgold':'#F4D03F','darkgold':'#B7950B'}

# Color reservation:
#   A_COLOR  = vermilion (A compartment, A-crest, speckle)
#   B_COLOR  = blue      (B compartment, B-trough, lamina)
#   STRUCT   = dark grey (CTCF anchors, loop arcs, TAD boundary, nucleosomes)
A_COLOR = WONG['vermil']
B_COLOR = WONG['blue']
STRUCT  = '#404040'   # dark grey for structural elements

fig, ax = plt.subplots(figsize=(15, 7.5))
ax.set_xlim(0, 15)
ax.set_ylim(-0.3, 6.5)
ax.axis('off')

# Title
ax.text(7.5, 6.15, 'A new level in the hierarchy of chromosome organisation',
        fontsize=13, fontweight='bold', ha='center', family='DejaVu Sans')

# Layer-disciplined legend strip (top-right):
# Three rows, each with its own color usage, so the reader sees the three
# DIFFERENT layers that the same vermilion/blue palette marks across the figure
# rather than conflating them under one row.
leg_x = 10.4
ax.text(leg_x, 5.95, 'colour key (three layers, all aligned along the speckle–lamina axis):',
        fontsize=7, ha='left', va='center', color='0.3', style='italic', fontweight='bold')
# Row 1: A/B compartments (categorical, ~5–10 Mb)
ax.add_patch(Rectangle((leg_x + 0.05, 5.78), 0.12, 0.12, fc=A_COLOR, ec='black', linewidth=0.5))
ax.add_patch(Rectangle((leg_x + 0.20, 5.78), 0.12, 0.12, fc=B_COLOR, ec='black', linewidth=0.5))
ax.text(leg_x + 0.40, 5.84, 'A / B compartments  (categorical, $\\sim$5–10 Mb)',
        fontsize=7, ha='left', va='center', color='0.15')
# Row 2: speckles / lamina (subnuclear bodies)
ax.add_patch(Circle((leg_x + 0.11, 5.62), 0.05, fc=A_COLOR, ec='black', linewidth=0.4))
ax.add_patch(Circle((leg_x + 0.26, 5.62), 0.05, fc=B_COLOR, ec='black', linewidth=0.4))
ax.text(leg_x + 0.40, 5.62, 'speckles / lamina  (subnuclear bodies)',
        fontsize=7, ha='left', va='center', color='0.15')
# Row 3: wave (its own gold colour — DIFFERENT layer)
ax.plot([leg_x + 0.06, leg_x + 0.32],
        [5.45, 5.45], color=WONG['darkgold'], lw=2.0)
ax.text(leg_x + 0.40, 5.45, 'the wave  (chromosome chain alternating between the two)',
        fontsize=7, ha='left', va='center', color='0.15')

# Vertical y-baseline for the 6-level row
y_row = 4.0

# ─── Level 1: Nucleosomes ────────────────────────────────────────────────
xc = 1.0
ax.text(xc, 5.45, '1. Nucleosomes', fontsize=10, ha='center', fontweight='bold')
for x in [0.50, 0.75, 1.00, 1.25, 1.50]:
    ax.add_patch(Circle((x, y_row), 0.10, fc=STRUCT, ec='black', linewidth=0.6))
ax.plot([0.40, 1.60], [y_row, y_row], color=STRUCT, lw=0.5, zorder=0)
ax.text(xc, y_row - 0.55, '~ 147 bp / nucleosome\n~ 10 nm',
        fontsize=8, ha='center', style='italic')

ax.annotate('', xy=(2.0, y_row), xytext=(1.7, y_row),
            arrowprops=dict(arrowstyle='->', color='black', lw=1))

# ─── Level 2: Loops ─────────────────────────────────────────────────────
xc = 3.0
ax.text(xc, 5.45, '2. Loops', fontsize=10, ha='center', fontweight='bold')
ax.add_patch(Arc((xc, y_row), 1.4, 1.0, theta1=0, theta2=180,
                  edgecolor=STRUCT, lw=1.6))
ax.plot([xc-0.7, xc+0.7], [y_row, y_row], color=STRUCT, lw=0.5, ls=':')
# CTCF anchors as black diamonds (not vermilion)
for cx in [xc-0.7, xc+0.7]:
    ax.scatter([cx], [y_row], marker='D', s=42, c='black', edgecolor='black',
               linewidth=0.4, zorder=4)
ax.text(xc - 0.85, y_row + 0.18, 'CTCF', fontsize=6.5, ha='center', color='black')
ax.text(xc, y_row - 0.55, '~ 100 kb\nCTCF-anchored',
        fontsize=8, ha='center', style='italic')

ax.annotate('', xy=(3.95, y_row), xytext=(3.7, y_row),
            arrowprops=dict(arrowstyle='->', color='black', lw=1))

# ─── Level 3: TADs ──────────────────────────────────────────────────────
xc = 5.0
ax.text(xc, 5.45, '3. TADs', fontsize=10, ha='center', fontweight='bold')
for offset, w, h in [(-0.4, 0.7, 0.4), (0.3, 0.5, 0.3)]:
    ax.add_patch(Arc((xc + offset, y_row), w, h, theta1=0, theta2=180,
                      edgecolor=STRUCT, lw=1.0))
ax.add_patch(FancyBboxPatch((xc-0.85, y_row-0.30), 1.7, 0.6,
                              boxstyle='round,pad=0.05',
                              fc='none', ec=STRUCT, lw=1.2,
                              linestyle='--'))
ax.text(xc, y_row - 0.55, '~ 1 Mb\nself-interacting domain',
        fontsize=8, ha='center', style='italic')

ax.annotate('', xy=(5.95, y_row), xytext=(5.7, y_row),
            arrowprops=dict(arrowstyle='->', color='black', lw=1))

# ─── Level 4: A/B compartments ───────────────────────────────────────────
xc = 7.0
ax.text(xc, 5.45, '4. A/B compartments', fontsize=10, ha='center', fontweight='bold')
colors_alt = [A_COLOR, B_COLOR, A_COLOR, B_COLOR, A_COLOR]
labels_alt = ['A','B','A','B','A']
for i, (col, lab) in enumerate(zip(colors_alt, labels_alt)):
    x0 = xc - 0.85 + i * 0.34
    ax.add_patch(Rectangle((x0, y_row-0.15), 0.30, 0.30, fc=col, ec='black',
                           linewidth=0.4, alpha=0.85))
    ax.text(x0 + 0.15, y_row, lab, fontsize=8, ha='center', va='center',
            fontweight='bold', color='white')
ax.text(xc, y_row - 0.55, '~ 5–10 Mb\nspeckle ↔ lamina',
        fontsize=8, ha='center', style='italic')

ax.annotate('', xy=(7.95, y_row), xytext=(7.7, y_row),
            arrowprops=dict(arrowstyle='->', color='black', lw=1))

# ─── Level 5: WAVE (highlighted, NEW) ────────────────────────────────────
# Wolf-fix 2026-05-02 (v4): the v3 fix coloured the wave halves vermilion/blue,
# but that conflated three distinct layers (A/B compartments at box 4; radial
# halves of the wave; speckles/lamina in the bottom panel) under the same
# palette. This version restores GOLD as the wave's own structural identifier
# and uses small grey directional arrows ("→ speckle interior / → lamina
# periphery") to convey the wave's mapping to nuclear environments WITHOUT
# re-using the compartment-and-speckle colour vocabulary inside the wave.
xc = 9.5
y_amp_w = 0.40
ax.add_patch(FancyBboxPatch((xc-1.25, y_row-1.0), 2.5, 2.6,
                              boxstyle='round,pad=0.05',
                              fc=WONG['lightgold'], ec=WONG['darkgold'],
                              lw=2, alpha=0.30))
ax.text(xc, 5.45, 'NEW: 5. Wave', fontsize=10.5, ha='center', fontweight='bold',
        color=WONG['darkgold'])
# Wave traced in gold (its own structural colour, not a compartment/body colour).
# Five full cycles over the chromosome length — matches the manuscript's N ≈ 5
# claim and the "5 cycles per chromosome" annotation.
xs = np.linspace(xc-1.0, xc+1.0, 800)
ys = y_row + y_amp_w * np.sin((xs - xc + 1.0) * np.pi * 5.0)  # 5 full cycles
ax.plot(xs, ys, color=WONG['darkgold'], lw=2.0, zorder=4)
# Faint centreline (no colour bands; keep the wave's two halves visually neutral)
ax.plot([xc-1.0, xc+1.0], [y_row, y_row], color='0.5', lw=0.5, ls='--', zorder=2)
# Small grey directional arrows + text on the LEFT, OUTSIDE the wave area, indicating
# what the two halves map to. No colour reuse: arrows + text in 0.35 grey.
ax.annotate('', xy=(xc-1.10, y_row + y_amp_w*0.85),
            xytext=(xc-1.10, y_row + 0.05),
            arrowprops=dict(arrowstyle='->', color='0.35', lw=0.6))
ax.text(xc-1.13, y_row + y_amp_w*0.55, 'speckle\ninterior', fontsize=6.0,
        color='0.35', ha='right', va='center', style='italic')
ax.annotate('', xy=(xc-1.10, y_row - y_amp_w*0.85),
            xytext=(xc-1.10, y_row - 0.05),
            arrowprops=dict(arrowstyle='->', color='0.35', lw=0.6))
ax.text(xc-1.13, y_row - y_amp_w*0.55, 'lamina\nperiphery', fontsize=6.0,
        color='0.35', ha='right', va='center', style='italic')
# 5-cycles-per-chromosome annotation across the top of the wave
ax.annotate('', xy=(xc+0.9, y_row + y_amp_w + 0.20),
            xytext=(xc-0.9, y_row + y_amp_w + 0.20),
            arrowprops=dict(arrowstyle='<->', color='0.5', lw=0.6))
ax.text(xc, y_row + y_amp_w + 0.34, '~ 5 cycles per chromosome',
        fontsize=7, color='0.3', fontweight='bold', ha='center')

ax.text(xc, y_row - 0.85,
        '~ 25–50 Mb / cycle\n$T \\propto L^{0.83}$, $N \\approx 5$ cycles/chromosome',
        fontsize=8, ha='center', style='italic',
        bbox=dict(boxstyle='round,pad=0.2', fc='white', ec=WONG['darkgold'], lw=0.8))

ax.annotate('', xy=(11.5, y_row), xytext=(11.0, y_row),
            arrowprops=dict(arrowstyle='->', color='black', lw=1))

# ─── Level 6: Chromosome territory ──────────────────────────────────────
xc = 12.7
ax.text(xc, 5.45, '6. Chr territory', fontsize=10, ha='center', fontweight='bold')
# Two soft-grey ellipses (no biology color reuse)
ax.add_patch(Ellipse((xc, y_row), 1.6, 1.2, angle=20,
                      fc=WONG['grey'], ec='black', linewidth=0.6, alpha=0.30))
ax.add_patch(Ellipse((xc-0.1, y_row), 1.2, 0.9, angle=-15,
                      fc=WONG['grey'], ec='black', linewidth=0.5, alpha=0.45))
ax.text(xc, y_row - 0.55, '~ 250 Mbp\nwhole-chromosome volume',
        fontsize=8, ha='center', style='italic')

# ════════════════════════════════════════════════════════════════════════
# BOTTOM PANEL — radial accordion within ONE chromosome territory
# Geometry: chromosome chain runs HORIZONTALLY across the territory; radial
# direction is VERTICAL (top = interior near speckles, bottom = periphery
# near lamina). With a horizontal chain and 5 cycles, each cycle has ample
# horizontal room and reads as a clear up-and-down wave.
# ════════════════════════════════════════════════════════════════════════
ax.text(7.5, 2.30,
        'The wave: a radial accordion within one chromosome territory in the nucleus',
        fontsize=11, fontweight='bold', ha='center', style='italic')

# Nuclear envelope ellipse (large, black outline)
nuc_x, nuc_y = 7.5, 0.95
nuc_w, nuc_h = 9.0, 1.95
ax.add_patch(Ellipse((nuc_x, nuc_y), nuc_w, nuc_h,
                      fc='#fafafa', ec='black', linewidth=1.5))
# Lamina layer (continuous blue band along the inner envelope)
for r_off in np.linspace(0.0, 0.07, 8):
    ax.add_patch(Ellipse((nuc_x, nuc_y), nuc_w - 2*r_off, nuc_h - 2*r_off,
                          fc='none', ec=B_COLOR, linewidth=0.9, alpha=0.18))
ax.text(nuc_x - nuc_w/2 - 0.10, nuc_y + 1.10, 'Nuclear envelope',
        fontsize=8, color='black', ha='left', style='italic')
ax.text(nuc_x - nuc_w/2 - 0.10, nuc_y + 0.92, 'Lamina (B-side, periphery)',
        fontsize=8.5, color=B_COLOR, fontweight='bold', ha='left')

# Speckle CLUSTER — compact body in the upper-interior of the territory
# (top of the chromosome region, since "interior" of the radial axis = top here)
speckle_cx, speckle_cy = nuc_x, nuc_y + 0.50
speckle_offsets = [
    (-0.30, +0.06), (-0.18, +0.16), (-0.10, +0.02), (-0.02, +0.12),
    (+0.06, -0.04), (+0.14, +0.08), (+0.22, -0.02), (+0.30, +0.10),
    (-0.06, +0.20), (+0.04, +0.20), (-0.22, -0.04), (+0.18, +0.18),
]
for dx, dy in speckle_offsets:
    ax.add_patch(Circle((speckle_cx + dx, speckle_cy + dy), 0.06,
                        fc=A_COLOR, ec='black', linewidth=0.4, zorder=5))
ax.text(speckle_cx, speckle_cy + 0.40, 'Speckles (A-side, interior)',
        fontsize=8.5, color=A_COLOR, fontweight='bold', ha='center')

# ONE chromosome territory occupying the lower-central region of the nucleus.
# Chain runs horizontally; radial direction (interior → periphery) is vertical.
terr_x_lo = nuc_x - 3.2     # left edge of territory (along chain)
terr_x_hi = nuc_x + 3.2     # right edge of territory
terr_y_top = nuc_y + 0.40   # interior side (touching speckle body region)
terr_y_bot = nuc_y - 0.78   # periphery side (touching lamina)

# Territory boundary — dashed grey rounded box
ax.add_patch(FancyBboxPatch((terr_x_lo - 0.12, terr_y_bot - 0.12),
                             (terr_x_hi - terr_x_lo) + 0.24,
                             (terr_y_top - terr_y_bot) + 0.24,
                             boxstyle='round,pad=0.05',
                             fc='none', ec=WONG['grey'], lw=0.8,
                             linestyle='--', alpha=0.7))
ax.text(terr_x_hi + 0.30, terr_y_top + 0.05,
        'one chromosome\nterritory', fontsize=7, color=WONG['grey'], ha='left',
        va='top', style='italic')

# Wave trace: x = chain coordinate (horizontal), y = radial position (vertical)
n_pts = 800
chain = np.linspace(0, 1, n_pts)        # along-chromosome coordinate
n_cycles = 5
# y oscillates between terr_y_top (interior, A-side, cos=+1) and terr_y_bot (periphery, B-side, cos=-1)
y_amp = (terr_y_top - terr_y_bot) / 2.0
y_centre = (terr_y_top + terr_y_bot) / 2.0
xs_w = terr_x_lo + (terr_x_hi - terr_x_lo) * chain
ys_w = y_centre + y_amp * np.cos(2*np.pi*n_cycles*chain)
ax.plot(xs_w, ys_w, color=WONG['darkgold'], lw=2.4, alpha=0.90, zorder=4)

# Mark A-crests (interior, vermilion) and B-troughs (periphery, blue)
for k in range(n_cycles):
    # A-crest at chain position k/n_cycles → cos = +1 → y = top (interior)
    chain_cr = k / n_cycles
    x_cr = terr_x_lo + (terr_x_hi - terr_x_lo) * chain_cr
    y_cr = terr_y_top
    ax.add_patch(Circle((x_cr, y_cr), 0.07, fc=A_COLOR, ec='black',
                        linewidth=0.5, zorder=6))
    # B-trough at chain position (k+0.5)/n_cycles → cos = −1 → y = bottom (periphery)
    chain_tr = (k + 0.5) / n_cycles
    x_tr = terr_x_lo + (terr_x_hi - terr_x_lo) * chain_tr
    y_tr = terr_y_bot
    ax.add_patch(Circle((x_tr, y_tr), 0.07, fc=B_COLOR, ec='black',
                        linewidth=0.5, zorder=6))

# Final right-side A-crest at chain=1
ax.add_patch(Circle((terr_x_hi, terr_y_top), 0.07, fc=A_COLOR, ec='black',
                    linewidth=0.5, zorder=6))

# Annotate "5 cycles" along the chain axis
ax.annotate('', xy=(terr_x_hi, terr_y_bot - 0.18),
            xytext=(terr_x_lo, terr_y_bot - 0.18),
            arrowprops=dict(arrowstyle='<->', color=WONG['grey'], lw=0.7))
ax.text((terr_x_lo + terr_x_hi)/2, terr_y_bot - 0.36,
        'one chromosome chain — N ≈ 5 radial cycles',
        fontsize=8, color=WONG['darkgold'], fontweight='bold', ha='center')

# Chain colour key (legend)
ax.plot([nuc_x - nuc_w/2 - 0.10, nuc_x - nuc_w/2 + 0.05],
        [nuc_y - 1.05, nuc_y - 1.05], color=WONG['darkgold'], lw=2.4)
ax.text(nuc_x - nuc_w/2 + 0.10, nuc_y - 1.05,
        'chromosome chain (along-chromosome coordinate runs horizontally;\n'
        'radial position oscillates between speckle interior and lamina periphery)',
        fontsize=7.5, color=WONG['darkgold'], fontweight='bold', ha='left',
        va='center')

# Save
plt.tight_layout()
ROOT = Path('/sessions/kind-brave-babbage/mnt/Wavelet')
out_dirs = [
    ROOT/'submission_FINAL_v24_April16/02_figures/main',
    ROOT/'submission_FINAL_v24_April16/01_manuscript/figures',
    ROOT/'submission_bundle_v95/02_figures/main',
    ROOT/'submission_bundle_v95/03_figures_to_edit/main',
]
for d in out_dirs:
    d.mkdir(parents=True, exist_ok=True)

DRAFT = ROOT/'figure_regen_2026-05-02/_drafts/hierarchy_schematic_v2'
DRAFT.parent.mkdir(parents=True, exist_ok=True)
plt.savefig(str(DRAFT) + '.png', dpi=300, bbox_inches='tight')
plt.savefig(str(DRAFT) + '.svg', bbox_inches='tight')
print(f'[wrote draft] {DRAFT}.png + .svg')

if os.environ.get('PROMOTE') == '1':
    for d in out_dirs:
        plt.savefig(str(d/'hierarchy_schematic.png'), dpi=300, bbox_inches='tight')
        plt.savefig(str(d/'hierarchy_schematic.svg'), bbox_inches='tight')
        print(f'[promoted] {d}/hierarchy_schematic.png+.svg')
plt.close(fig)
