"""
Generate synthetic Raman spectra of boron-doped silicon for testing
the continuous learning pipeline (knowledge synthesis → graduation → skill updates).

Physics modeled:
  - Fano lineshape (asymmetric phonon-plasmon coupling in doped Si)
  - Peak downshift ~0.3 cm⁻¹ per 1e19 cm⁻³ boron increase
  - FWHM broadening with doping
  - Fano |q| decreases (stronger asymmetry) above ~5e19 cm⁻³
  - One fluorescence-dominated failure case (polymer-coated sample)

Usage:
    python examples/continuous_learning_demo.py              # default output dir
    python examples/continuous_learning_demo.py --output-dir /tmp/raman_data

Outputs:
    <output_dir>/
        B_0.5e19.csv     ← lightly doped, nearly Lorentzian
        B_2.0e19.csv
        B_5.0e19.csv     ← Fano asymmetry becomes visible
        B_9.0e19.csv
        B_15.0e19.csv    ← strong Fano, large downshift
        B_20.0e19.csv    ← extreme doping, near metallic transition
        polymer_coated.csv  ← fluorescence failure
        ground_truth.json   ← true parameters for each spectrum
"""

import argparse
import json
from pathlib import Path

import numpy as np


def fano_lineshape(x, center, gamma, q, amplitude, bg_slope=0, bg_intercept=100):
    """Fano (Breit-Wigner-Fano) profile on a linear background."""
    epsilon = (x - center) / gamma
    fano = amplitude * (q + epsilon) ** 2 / (1 + epsilon ** 2)
    return fano + bg_slope * x + bg_intercept


def generate_doped_si_spectrum(boron_concentration, rng):
    """Generate a synthetic Raman spectrum for B-doped Si.

    Returns (x, y, ground_truth_params).
    """
    x = np.linspace(490, 550, 500)

    conc_units = boron_concentration / 1e19
    center = 520.7 - 0.3 * conc_units + rng.normal(0, 0.05)
    gamma = 2.0 + 0.15 * conc_units + rng.normal(0, 0.1)
    q = max(-30.0 + 1.5 * conc_units, -2.0) + rng.normal(0, 0.3)
    amplitude = 8000 + rng.normal(0, 200)
    noise_level = 30 + 2 * conc_units

    y = fano_lineshape(x, center, gamma, q, amplitude)
    y += rng.normal(0, noise_level, size=len(x))

    params = {
        "boron_concentration_cm3": boron_concentration,
        "center_cm1": round(center, 2),
        "gamma_cm1": round(gamma, 2),
        "fwhm_cm1": round(2 * gamma, 2),
        "q": round(q, 2),
        "noise_level": round(noise_level, 1),
    }
    return x, y, params


def main():
    parser = argparse.ArgumentParser(description="Generate synthetic B-doped Si Raman spectra")
    parser.add_argument("--output-dir", default="./examples/data/boron_doped_si",
                        help="Directory to write CSV files and ground truth")
    args = parser.parse_args()

    out = Path(args.output_dir)
    out.mkdir(parents=True, exist_ok=True)

    rng = np.random.default_rng(42)
    ground_truth = {}

    # ── Doped Si series ──────────────────────────────────────────────────
    concentrations = [0.5e19, 2.0e19, 5.0e19, 9.0e19, 15.0e19, 20.0e19]
    for conc in concentrations:
        x, y, params = generate_doped_si_spectrum(conc, rng)
        label = f"B_{conc/1e19:.1f}e19"
        fname = f"{label}.csv"
        np.savetxt(out / fname, np.column_stack([x, y]),
                   delimiter=",", header="Raman_Shift_cm-1,Intensity", comments="")
        ground_truth[fname] = params
        print(f"  {fname:25s}  center={params['center_cm1']:6.2f} cm⁻¹  "
              f"FWHM={params['fwhm_cm1']:5.2f}  q={params['q']:6.2f}")

    # ── Fluorescence failure ─────────────────────────────────────────────
    x_fail = np.linspace(200, 800, 500)
    fluorescence = 50000 * np.exp(-0.5 * ((x_fail - 500) / 150) ** 2)
    y_fail = fluorescence + rng.normal(0, 500, size=len(x_fail))
    np.savetxt(out / "polymer_coated.csv", np.column_stack([x_fail, y_fail]),
               delimiter=",", header="Raman_Shift_cm-1,Intensity", comments="")
    ground_truth["polymer_coated.csv"] = {"note": "fluorescence failure, no Raman peaks"}
    print(f"  {'polymer_coated.csv':25s}  (fluorescence failure — no Raman peaks)")

    # ── Save ground truth ────────────────────────────────────────────────
    with open(out / "ground_truth.json", "w") as f:
        json.dump(ground_truth, f, indent=2, default=str)

    print(f"\n  Wrote {len(concentrations) + 1} spectra + ground_truth.json to {out}/")


if __name__ == "__main__":
    main()
