/**
 * @file impulse.c
 * @brief Example: generate a discrete impulse and visualise its spectrum.
 *
 * This program demonstrates MD_impulse() by:
 *   1. Generating a unit impulse (Kronecker delta) at sample 0.
 *   2. Computing its magnitude spectrum via MD_magnitude_spectrum().
 *   3. Writing the results to CSV and to an interactive HTML visualisation
 *      with both time-domain and frequency-domain plots.
 *
 * Build and run (from the repository root):
 *   make                          # build libminidsp.a first
 *   make -C examples plot         # build example, run it, generate HTML
 *   open examples/impulse.html    # interactive plots
 */

#include <stdio.h>
#include <stdlib.h>
#include "minidsp.h"
#include "plot_html.h"

/* -----------------------------------------------------------------------
 * Write the interactive HTML visualisation.
 *
 * Two Plotly plots: time-domain impulse and its magnitude spectrum.
 * -----------------------------------------------------------------------*/
static int write_html(const char *path,
                      const double *signal, const double *freqs,
                      const double *mags, unsigned N, unsigned num_bins,
                      double sample_rate)
{
    FILE *fp = fopen(path, "w");
    if (!fp) {
        fprintf(stderr, "cannot open %s for writing\n", path);
        return -1;
    }

    char subtitle[256];
    snprintf(subtitle, sizeof(subtitle),
        "unit impulse at sample 0 &nbsp;|&nbsp;\n"
        "    sample rate %.0f Hz &nbsp;|&nbsp;\n"
        "    FFT size %u",
        sample_rate, N);

    plot_html_begin(fp, "Impulse Spectrum", subtitle, 0);

    fprintf(fp,
        "  <div id=\"time-plot\" class=\"plot-container\"></div>\n"
        "  <div id=\"freq-plot\" class=\"plot-container\"></div>\n"
        "  <div class=\"info\">\n"
        "    <strong>What you are seeing:</strong><br>\n"
        "    A unit impulse is a single spike at sample 0 &mdash; all other\n"
        "    samples are zero.  Its magnitude spectrum is perfectly flat\n"
        "    because a single spike contains equal energy at every frequency.\n"
        "    This makes the impulse ideal for testing filters: feed it in,\n"
        "    and the output <em>is</em> the filter's impulse response.\n"
        "  </div>\n\n");

    /* ---- Embed data as JS arrays ---- */
    fprintf(fp, "  <script>\n");
    fprintf(fp, "    // Data generated by impulse.c\n");

    /* Sample indices for the time-domain plot */
    fprintf(fp, "    const samples = [");
    for (unsigned i = 0; i < N; i++) {
        fprintf(fp, "%u", i);
        if (i + 1 < N) fprintf(fp, ",");
    }
    fprintf(fp, "];\n");

    plot_html_js_array(fp, "signal", signal, N, "%.1f");
    plot_html_js_array(fp, "freqs", freqs, num_bins, "%.4f");
    plot_html_js_array(fp, "mags", mags, num_bins, "%.8f");
    fprintf(fp, "\n");

    /* ---- Time-domain plot ---- */
    fprintf(fp,
        "    Plotly.newPlot('time-plot', [{\n"
        "      x: samples, y: signal,\n"
        "      type: 'scatter', mode: 'markers',\n"
        "      marker: { color: '#2563eb', size: 4 },\n"
        "      name: 'Amplitude',\n"
        "      hovertemplate: 'Sample %%{x}<br>Amplitude: %%{y:.1f}<extra></extra>'\n"
        "    }], {\n"
        "      title: { text: 'Unit Impulse (Time Domain)', font: { size: 15 } },\n"
        "      xaxis: { title: 'Sample index', range: [-1, %u] },\n"
        "      yaxis: { title: 'Amplitude', range: [-0.15, 1.25] },\n"
        "      margin: { t: 55, r: 30, b: 55, l: 65 },\n"
        "      height: 300\n"
        "    }, { responsive: true });\n\n",
        N < 64 ? N : 64);

    /* ---- Frequency-domain plot ---- */
    fprintf(fp,
        "    Plotly.newPlot('freq-plot', [{\n"
        "      x: freqs, y: mags,\n"
        "      type: 'scatter', mode: 'lines',\n"
        "      line: { color: '#2563eb', width: 1.2 },\n"
        "      name: 'Amplitude',\n"
        "      hovertemplate: '%%{x:.1f} Hz<br>Amplitude: %%{y:.6f}<extra></extra>'\n"
        "    }], {\n"
        "      title: { text: 'Magnitude Spectrum (Flat)', font: { size: 15 } },\n"
        "      xaxis: { title: 'Frequency (Hz)', range: [0, %.1f] },\n"
        "      yaxis: { title: 'Amplitude' },\n"
        "      margin: { t: 55, r: 30, b: 55, l: 65 },\n"
        "      height: 380\n"
        "    }, { responsive: true });\n"
        "  </script>\n",
        sample_rate / 2.0);

    plot_html_end(fp);
    fclose(fp);
    return 0;
}

int main(void)
{
    /* ------------------------------------------------------------------
     * Signal parameters
     * ----------------------------------------------------------------*/
    const unsigned N           = 1024;      /* FFT size (samples)    */
    const double   sample_rate = 44100.0;   /* Hz                    */
    const double   amplitude   = 1.0;
    const unsigned position    = 0;         /* spike at sample 0     */
    const unsigned num_bins    = N / 2 + 1;

    /* ------------------------------------------------------------------
     * Generate the impulse using MD_impulse
     * ----------------------------------------------------------------*/
    double *signal = malloc(N * sizeof(double));
    double *mag    = malloc(num_bins * sizeof(double));
    double *freqs  = malloc(num_bins * sizeof(double));

    if (!signal || !mag || !freqs) {
        fprintf(stderr, "allocation failed\n");
        return 1;
    }

    //! [generate-impulse]
    MD_impulse(signal, N, amplitude, position);
    //! [generate-impulse]

    /* ------------------------------------------------------------------
     * Compute the magnitude spectrum
     * ----------------------------------------------------------------*/
    MD_magnitude_spectrum(signal, N, mag);

    /* Convert to single-sided amplitude spectrum */
    for (unsigned k = 0; k < num_bins; k++) {
        freqs[k] = (double)k * sample_rate / (double)N;
        mag[k] /= (double)N;
        if (k > 0 && k < N / 2)
            mag[k] *= 2.0;
    }

    /* ------------------------------------------------------------------
     * Write results to CSV
     * ----------------------------------------------------------------*/
    const char *csv_file = "impulse.csv";
    FILE *fp = fopen(csv_file, "w");
    if (!fp) {
        fprintf(stderr, "cannot open %s for writing\n", csv_file);
        return 1;
    }

    fprintf(fp, "bin,frequency_hz,magnitude\n");
    for (unsigned k = 0; k < num_bins; k++)
        fprintf(fp, "%u,%.4f,%.8f\n", k, freqs[k], mag[k]);
    fclose(fp);

    printf("Wrote %u frequency bins to %s\n", num_bins, csv_file);

    /* ------------------------------------------------------------------
     * Write interactive HTML visualisation
     * ----------------------------------------------------------------*/
    const char *html_file = "impulse.html";
    if (write_html(html_file, signal, freqs, mag, N, num_bins,
                   sample_rate) == 0) {
        printf("Wrote interactive plot to %s\n", html_file);
    }

    printf("Signal: unit impulse at sample %u, amplitude %.1f\n",
           position, amplitude);
    printf("Sample rate: %.0f Hz, FFT size: %u\n", sample_rate, N);

    /* ------------------------------------------------------------------
     * Cleanup
     * ----------------------------------------------------------------*/
    free(freqs);
    free(mag);
    free(signal);
    MD_shutdown();

    return 0;
}
