"""Analyse hors ligne d'un signal synthétique. Dépendances : numpy, matplotlib."""
import argparse
import csv
from pathlib import Path

import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
import numpy as np


def main(output):
    sample_rate = 500_000
    center_hz = 433_800_000
    offset_hz = 120_000
    time = np.arange(75_000) / sample_rate
    rng = np.random.default_rng(433920)
    active = np.zeros(time.size, dtype=bool)
    for start in (15, 60, 105):
        active[start * 500:(start + 20) * 500] = True

    noise = 0.18 * (rng.standard_normal(time.size) + 1j * rng.standard_normal(time.size))
    samples = noise + active * np.exp(2j * np.pi * offset_hz * time)

    # Recherche du maximum spectral sur les échantillons complexes.
    frequencies = center_hz + np.fft.fftshift(np.fft.fftfreq(samples.size, 1 / sample_rate))
    spectrum = np.abs(np.fft.fftshift(np.fft.fft(samples * np.hanning(samples.size))))
    peak_hz = frequencies[np.argmax(spectrum)]
    db_relative = 20 * np.log10(np.maximum(spectrum / spectrum.max(), 1e-8))

    # Mesure de la puissance par fenêtres de 1 ms.
    power = np.mean(np.abs(samples.reshape(-1, 500)) ** 2, axis=1)
    threshold = 4 * np.median(power[:10])
    above = power >= threshold
    transitions = np.diff(np.r_[0, above.astype(int), 0])
    starts = np.flatnonzero(transitions == 1)
    stops = np.flatnonzero(transitions == -1)
    bursts = [(start, stop, stop - start) for start, stop in zip(starts, stops, strict=True)]

    output.mkdir(parents=True, exist_ok=True)
    with (output / "rf-resultats.csv").open("w", newline="", encoding="utf-8") as file:
        writer = csv.writer(file)
        writer.writerow(["frequence_pic_hz", "debut_ms", "fin_ms", "duree_ms"])
        writer.writerows((int(peak_hz), *burst) for burst in bursts)

    with plt.style.context("dark_background"):
        fig, (ax_fft, ax_time) = plt.subplots(2, 1, figsize=(10, 5.5), layout="constrained")
        figure_title = fig.suptitle("Banc d’essai numérique · Signal synthétique")
        ax_fft.plot(frequencies / 1e6, db_relative, color="#8be9bf", linewidth=0.7)
        ax_fft.axvline(peak_hz / 1e6, color="#ffcc80", linestyle="--")
        ax_fft.set(xlim=(433.75, 434.05), ylim=(-85, 5), xlabel="Fréquence (MHz)",
                   ylabel="Niveau relatif (dB)",
                   title=f"Maximum spectral · {peak_hz / 1e6:.3f} MHz · BorelTO · simulation")
        ax_fft.add_patch(Rectangle((peak_hz / 1e6 - 0.008, -20), 0.016, 24,
                                   fill=False, edgecolor="#ff5757", linewidth=1.5))
        ax_fft.ticklabel_format(axis="x", style="plain", useOffset=False)
        ax_time.step(np.arange(power.size), power, where="post", color="#ffcc80", label="Puissance moyenne")
        ax_time.axhline(threshold, color="#8be9bf", linestyle="--", label="Seuil")
        ax_time.set(xlim=(0, 150), xlabel="Temps (ms)", ylabel="Puissance (u.a.)",
                    title="Détection des salves · BorelTO · simulation")
        ax_time.add_patch(Rectangle((15, threshold), 20, 1.15 - threshold,
                                    fill=False, edgecolor="#ff5757", linewidth=1.5))
        ax_time.legend(loc="upper right")
        for axis in (ax_fft, ax_time):
            axis.grid(alpha=0.2)
        figure_title.set_visible(False)
        for axis, name in ((ax_fft, "simulation-spectre.png"), (ax_time, "simulation-salves.png")):
            for panel in (ax_fft, ax_time):
                panel.set_visible(panel is axis)
            fig.savefig(output / name, dpi=160, bbox_inches="tight", pad_inches=0.12)
        for axis in (ax_fft, ax_time):
            axis.set_visible(True)
        figure_title.set_visible(True)
        svg_path = output / "telecommande-rf-simulation.svg"
        fig.savefig(svg_path, metadata={"Date": None})
        svg_path.write_text(
            "\n".join(line.rstrip() for line in svg_path.read_text(encoding="utf-8").splitlines()) + "\n",
            encoding="utf-8",
        )
        plt.close(fig)


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--sortie", type=Path, default=Path("resultats-rf"))
    main(parser.parse_args().sortie)
