#!/usr/bin/env python3
"""Generate deterministic visuals for the numbered formulas in Chapter 1."""

from __future__ import annotations

from pathlib import Path

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np

ROOT = Path(__file__).resolve().parents[3]
SVG = ROOT / "assets/figures/svg"
SVG.mkdir(parents=True, exist_ok=True)

RED = "#7F1D1D"
TEAL = "#0F766E"
BLUE = "#1D4ED8"
PURPLE = "#7C3AED"
GOLD = "#B45309"
GRAY = "#6B7280"
BLACK = "#111827"

plt.rcParams.update(
    {
        "font.family": "DejaVu Sans",
        "font.size": 9,
        "axes.spines.top": False,
        "axes.spines.right": False,
        "axes.titleweight": "bold",
        "svg.fonttype": "none",
    }
)


def save(fig: plt.Figure, filename: str) -> None:
    fig.savefig(SVG / filename, bbox_inches="tight")
    plt.close(fig)


def zero_line(axis: plt.Axes) -> None:
    axis.axhline(0.0, color=GRAY, linewidth=0.6)


# Equation 1.1: amplitude, frequency, period, and phase in one sinusoid.
t = np.linspace(0.0, 1.25, 1600)
amplitude = 0.8
frequency = 2.0
phase = np.pi / 4
signal = amplitude * np.sin(2 * np.pi * frequency * t + phase)
unshifted = amplitude * np.sin(2 * np.pi * frequency * t)
fig, axis = plt.subplots(figsize=(7.2, 3.2), constrained_layout=True)
axis.plot(t, signal, color=RED, linewidth=2.0, label="φ = π/4")
axis.plot(t, unshifted, color=GRAY, linewidth=1.0, linestyle="--", label="φ = 0 reference")
axis.axhline(amplitude, color=TEAL, linewidth=0.8, linestyle=":", label="±A = ±0.8")
axis.axhline(-amplitude, color=TEAL, linewidth=0.8, linestyle=":")
axis.annotate("T = 1/f = 0.5 s", xy=(0.25, -1.02), xytext=(0.75, -1.02), ha="center", va="center", arrowprops={"arrowstyle": "<->", "color": BLACK})
axis.set(xlabel="time t (s)", ylabel="s(t)", xlim=(0, 1.25), ylim=(-1.15, 1.15), title="Equation 1.1: A = 0.8, f = 2 Hz, φ = π/4")
axis.legend(frameon=False, ncol=3, loc="upper right")
save(fig, "eq-1-1-sinusoid.svg")

# Equation 1.2: angular phase advances linearly and the sine reads that angle.
omega = 4 * np.pi
angle = omega * t + phase
fig, axes = plt.subplots(2, 1, figsize=(7.2, 4.8), sharex=True, constrained_layout=True)
axes[0].plot(t, angle / (2 * np.pi), color=BLUE, linewidth=2)
axes[0].set(ylabel="phase θ / 2π (cycles)", title="Angle advances at ω = 4π rad/s")
axes[1].plot(t, amplitude * np.sin(angle), color=RED, linewidth=1.8)
zero_line(axes[1])
axes[1].set(xlabel="time t (s)", ylabel="s(t)", title="The sine converts angle into amplitude")
fig.suptitle("Equation 1.2: s(t) = A sin(ωt + φ), A = 0.8, ω = 4π, φ = π/4", fontweight="bold")
save(fig, "eq-1-2-angular-frequency.svg")

# Equation 1.3: frequency is the reciprocal of period.
period_ms = np.linspace(1.0, 20.0, 800)
frequency_hz = 1000.0 / period_ms
fig, axis = plt.subplots(figsize=(7.2, 3.2), constrained_layout=True)
axis.plot(period_ms, frequency_hz, color=BLUE, linewidth=2)
for x, y, label in [(10.0, 100.0, "10 ms ↔ 100 Hz"), (1000 / 440, 440.0, "2.27 ms ↔ 440 Hz")]:
    axis.scatter([x], [y], color=RED, zorder=3)
    axis.annotate(label, (x, y), xytext=(8, 8), textcoords="offset points")
axis.set(xlabel="period T (ms)", ylabel="frequency f (Hz)", xlim=(1, 20), ylim=(0, 1020), title="Equation 1.3: shorter periods produce higher frequencies")
save(fig, "eq-1-3-period-frequency.svg")

# Equation 1.4: harmonic frequency grows linearly with harmonic number.
fundamental = 110.0
harmonic = np.arange(1, 7)
harmonic_hz = harmonic * fundamental
fig, axis = plt.subplots(figsize=(7.2, 3.2), constrained_layout=True)
markerline, stemlines, _ = axis.stem(harmonic, harmonic_hz, basefmt=" ")
plt.setp(markerline, color=RED, markersize=6)
plt.setp(stemlines, color=RED, linewidth=1.6)
for k, value in zip(harmonic, harmonic_hz):
    axis.annotate(f"{value:.0f}", (k, value), xytext=(0, 7), textcoords="offset points", ha="center")
axis.set(xticks=harmonic, xlabel="harmonic number k", ylabel="frequency fk (Hz)", ylim=(0, 720), title="Equation 1.4: fk = k f0 with f0 = 110 Hz")
save(fig, "eq-1-4-harmonic-family.svg")

# Equation 1.6: active harmonic indices 2, 4, and 6 repeat at 2f0.
fundamental = 100.0
active = np.array([2, 4, 6])
amplitudes = np.array([1.0, 0.5, 0.25])
t_short = np.linspace(0.0, 0.020, 2400, endpoint=False)
components = amplitudes[:, None] * np.sin(2 * np.pi * active[:, None] * fundamental * t_short)
summed = components.sum(axis=0)
fig, axes = plt.subplots(2, 1, figsize=(7.2, 5.2), constrained_layout=True)
axes[0].plot(t_short * 1000, summed, color=BLACK, linewidth=1.6)
for boundary in np.arange(0, 20.1, 5):
    axes[0].axvline(boundary, color=RED, linewidth=0.7, linestyle="--")
axes[0].annotate("repeat period = 5 ms", xy=(0, -1.65), xytext=(5, -1.65), ha="center", arrowprops={"arrowstyle": "<->", "color": RED})
axes[0].set(xlabel="time (ms)", ylabel="sum", ylim=(-1.85, 1.85), title="Waveform repeats twice per declared 100 Hz cycle")
markerline, stemlines, _ = axes[1].stem(active * fundamental, amplitudes, basefmt=" ")
plt.setp(markerline, color=PURPLE, markersize=6)
plt.setp(stemlines, color=PURPLE, linewidth=1.6)
axes[1].set(xlabel="frequency (Hz)", ylabel="relative amplitude", xticks=active * fundamental, ylim=(0, 1.1), title="Active indices {2, 4, 6} have gcd = 2")
fig.suptitle("Equation 1.6: frepeat = gcd(2, 4, 6) f0 = 200 Hz", fontweight="bold")
save(fig, "eq-1-6-gcd-repetition.svg")

# Equation 1.7: exact worked three-harmonic signal and spectrum.
fundamental = 110.0
amplitudes = np.array([1.0, 0.5, 0.25])
t_short = np.linspace(0.0, 0.030, 2400, endpoint=False)
components = amplitudes[:, None] * np.sin(2 * np.pi * np.arange(1, 4)[:, None] * fundamental * t_short)
summed = components.sum(axis=0)
fig, axes = plt.subplots(1, 2, figsize=(7.2, 3.3), constrained_layout=True)
axes[0].plot(t_short * 1000, summed, color=BLACK, linewidth=1.5)
zero_line(axes[0])
axes[0].set(xlabel="time (ms)", ylabel="x(t)", title="Three-harmonic waveform")
markerline, stemlines, _ = axes[1].stem([110, 220, 330], amplitudes, basefmt=" ")
plt.setp(markerline, color=RED, markersize=6)
plt.setp(stemlines, color=RED, linewidth=1.6)
axes[1].set(xlabel="frequency (Hz)", ylabel="relative amplitude", xticks=[110, 220, 330], ylim=(0, 1.1), title="One-sided amplitude spectrum")
fig.suptitle("Equation 1.7: f0 = 110 Hz, A = [1, 0.5, 0.25], phase = 0", fontweight="bold")
save(fig, "eq-1-7-worked-tone.svg")

print("Generated Chapter 1 formula visuals.")
