# /// script
# requires-python = "==3.12.*"
# dependencies = ["matplotlib"]
# ///

import sys
from pathlib import Path

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
from figure_quality import configure_matplotlib, figure_output_path, validate_figure

configure_matplotlib()

# --- Compute the difference table ---
seq = [0, 1, 8, 27, 64, 125]

rows = [seq]
while len(rows[-1]) > 1:
    prev = rows[-1]
    rows.append([prev[i + 1] - prev[i] for i in range(len(prev) - 1)])

# Stop at Δ⁴f (5 rows total); Δ⁵f = [0] is trivial and clutters the figure
rows = rows[:5]

# rows[0] = [0, 1, 8, 27, 64, 125]
# rows[1] = [1, 7, 19, 37, 61]
# rows[2] = [6, 12, 18, 24]
# rows[3] = [6, 6, 6]
# rows[4] = [0, 0]

# --- Layout constants ---
# We'll place values in a grid.
# Row r, column c: the cell is at position (r, c) where c=0..len(row)-1
# We want the triangle to have: row 0 at left edge x=0, each subsequent row
# indented by 0.5 cell widths so the diagonal left edge lines up nicely.

COL_W = 1.0  # width per cell in data units
ROW_H = 1.0  # height per row
INDENT = 0.5  # x indent per row (half cell)

N_ROWS = len(rows)  # 5
N_COLS = len(rows[0])  # 6

fig_w_in = 480 / 96  # ~5 inches at 96 dpi; will save at 300 dpi
fig_h_in = 3.2

fig, ax = plt.subplots(figsize=(fig_w_in, fig_h_in))
ax.set_aspect("equal")
ax.axis("off")

# Coordinate system: x left-to-right, y top-to-bottom (we'll invert yaxis)
# Row r is at y = r (0 at top)
# Cell (r, c) center is at x = r*INDENT + c*COL_W, y = r*ROW_H

BLUE = "#DBEAFE"
YELLOW_BG = "#fef9c3"
TEXT_DARK = "#111827"
TEXT_BLUE = "#111827"
CELL_H = 0.62
CELL_W = 0.80

# Constant row index: rows[3] = [6, 6, 6]
CONST_ROW = 3

# Draw cells
for r, row in enumerate(rows):
    for c, val in enumerate(row):
        cx = r * INDENT + c * COL_W
        cy = r * ROW_H

        is_left_edge = c == 0
        is_const_row = r == CONST_ROW

        # Background rect
        if is_left_edge:
            facecolor = BLUE
            textcolor = TEXT_BLUE
            zorder = 3
        elif is_const_row:
            facecolor = YELLOW_BG
            textcolor = TEXT_DARK
            zorder = 2
        else:
            facecolor = "white"
            textcolor = TEXT_DARK
            zorder = 1

        rect = mpatches.FancyBboxPatch(
            (cx - CELL_W / 2, cy - CELL_H / 2),
            CELL_W,
            CELL_H,
            boxstyle="round,pad=0.04",
            linewidth=0,
            facecolor=facecolor,
            edgecolor="none",
            zorder=zorder,
        )
        ax.add_patch(rect)

        ax.text(
            cx,
            cy,
            str(val),
            ha="center",
            va="center",
            fontsize=11,
            fontfamily="DejaVu Sans Mono",
            color=textcolor,
            fontweight="bold" if is_left_edge else "normal",
            zorder=zorder + 1,
        )

# Row labels on the right side
row_labels = [
    "f(n)",
    "Δf",
    "Δ²f",
    "Δ³f  ← constant",
    "Δ⁴f",
]
for r, label in enumerate(row_labels):
    last_c = len(rows[r]) - 1
    rx = r * INDENT + last_c * COL_W + COL_W * 0.65
    ry = r * ROW_H
    ax.text(
        rx,
        ry,
        label,
        ha="left",
        va="center",
        fontsize=10,
        color="#6b7280",
        style="italic" if "constant" in label else "normal",
    )

# Set axis limits with padding
total_w = (N_ROWS - 1) * INDENT + (N_COLS - 1) * COL_W
ax.set_xlim(-0.7, total_w + 2.2)
ax.set_ylim(-0.6, (N_ROWS - 1) * ROW_H + 0.6)
ax.invert_yaxis()

fig.patch.set_facecolor("white")
plt.tight_layout(pad=0.3)

validate_figure(fig)
out = figure_output_path(__file__, "cubes_table.png")
fig.savefig(out, dpi=300, bbox_inches="tight", facecolor="white")
print(f"Saved {out}")
