"""
Shared figure-style module for the 2026-05-02 real-data regen pass.

Single source of truth for:
  - Wong-friendly palette + semantic mapping
  - Typographic hierarchy (Nature-grade)
  - Panel-letter helper (one set of outer letters, never overlap)
  - savefig_both() — vector SVG + 300-dpi PNG, identical content

Hard rules (per FIGURE_DESIGN_STANDARDS.md, 2026-05-02):
  - NO np.random / rng calls in any script that imports this module
    except inside files explicitly named null_*.py (legitimate null models).
  - Panel letters lowercase a/b/c/... in 12 pt bold, top-left of axes,
    placed via fig.text in axes coords with offset (-0.10, +0.04).
  - Action titles state the finding, not the variable.
  - No inner "A. ..." / "B. ..." prefixes inside subplot titles.
"""
from __future__ import annotations
from pathlib import Path
import matplotlib.pyplot as plt
import matplotlib as mpl

# ---------- Palette ----------
WONG = {
    'blue':    '#0072B2',   # A / active / interior / speckle / G2
    'vermil':  '#D55E00',   # B / repressive / periphery / lamina / Prophase
    'orange':  '#E69F00',   # accent / warm
    'green':   '#009E73',   # supporting / null / OK
    'sky':     '#56B4E9',   # secondary blue
    'yellow':  '#F0E442',   # accent / mid
    'pink':    '#CC79A7',   # accent / contrast
    'grey':    '#7F7F7F',   # null / control
    'gold':    '#B8860B',   # KEY FINDING marker
    'black':   '#000000',
}

SEMANTIC = {
    'A':            WONG['blue'],
    'B':            WONG['vermil'],
    'active':       WONG['blue'],
    'repressive':   WONG['vermil'],
    'interior':     WONG['blue'],
    'periphery':    WONG['vermil'],
    'speckle':      WONG['blue'],
    'lamina':       WONG['vermil'],
    'null':         WONG['grey'],
    'control':      WONG['grey'],
    'key':          WONG['gold'],
    'G2':           WONG['blue'],
    'Prophase':     WONG['vermil'],
    'PM':           WONG['orange'],   # prometaphase variants
    'NS':           WONG['grey'],
}

PANEL_LETTER_OFFSET = (-0.10, 0.04)   # (dx, dy) in axes coords
PANEL_LETTER_FONTSIZE = 12

def apply_style():
    """Apply the project-canonical matplotlib rcParams."""
    mpl.rcParams.update({
        'font.family':      'sans-serif',
        'font.sans-serif':  ['DejaVu Sans', 'Arial', 'Helvetica'],
        'font.size':        9,
        'axes.titlesize':   10,
        'axes.titleweight': 'bold',
        'axes.labelsize':   9,
        'axes.linewidth':   0.6,
        'axes.spines.top':  False,
        'axes.spines.right': False,
        'axes.edgecolor':   '0.2',
        'xtick.labelsize':  8,
        'ytick.labelsize':  8,
        'xtick.major.width': 0.5,
        'ytick.major.width': 0.5,
        'xtick.major.size': 3,
        'ytick.major.size': 3,
        'legend.frameon':   False,
        'legend.fontsize':  8,
        'figure.dpi':       110,
        'savefig.dpi':      300,
        'savefig.bbox':     'tight',
        'svg.fonttype':     'none',   # keep text as <text>, not paths — editable
    })

def panel_letter(fig, ax, letter, dx=None, dy=None, fontsize=None):
    """Place a single bold lowercase panel letter at the top-left of an axis.
    Uses fig.text in axes-coord transform so the letter lives in figure space
    but tracks the axis position. One letter per axis. Never inside the panel.
    """
    if dx is None: dx = PANEL_LETTER_OFFSET[0]
    if dy is None: dy = PANEL_LETTER_OFFSET[1]
    if fontsize is None: fontsize = PANEL_LETTER_FONTSIZE
    fig.text(0, 0, letter,
             fontsize=fontsize, fontweight='bold',
             ha='right', va='bottom',
             transform=ax.transAxes + mpl.transforms.ScaledTranslation(dx, dy, fig.dpi_scale_trans))

def savefig_both(fig, basename: Path | str):
    """Write PNG (300 dpi) and SVG (vector, editable) with identical content.
    basename should NOT include extension. Both files written next to it.
    """
    basename = Path(basename)
    basename.parent.mkdir(parents=True, exist_ok=True)
    fig.savefig(basename.with_suffix('.png'), dpi=300, bbox_inches='tight', pad_inches=0.05)
    fig.savefig(basename.with_suffix('.svg'),               bbox_inches='tight', pad_inches=0.05)

def hero_gridspec(fig, hero_layout='top-wide'):
    """Returns a gridspec with a hero panel taking ~50% of figure area.
    hero_layout='top-wide': hero spans full top row, 3 panels in bottom row.
    hero_layout='left-tall': hero spans full left col, 3 panels in right col.
    """
    if hero_layout == 'top-wide':
        gs = fig.add_gridspec(2, 3, height_ratios=[1.6, 1.0], hspace=0.42, wspace=0.32)
        return gs[0, :], gs[1, 0], gs[1, 1], gs[1, 2]
    if hero_layout == 'left-tall':
        gs = fig.add_gridspec(3, 2, width_ratios=[1.6, 1.0], hspace=0.42, wspace=0.32)
        return gs[:, 0], gs[0, 1], gs[1, 1], gs[2, 1]
    raise ValueError(f"unknown hero_layout {hero_layout!r}")
