use crate::fm_demod::Sample;
use crate::iq_reader::FileSource;
use crate::pipeline::{AfterDemodPiplineExt, DspPipelineExt, SyncPipelineExt};
use egui_plot::{HLine, Line, Plot, VLine};
use indicatif::ProgressIterator;

mod agc;
mod dc_blocker;
mod fir;
mod fm_demod;
mod frame;
mod iq_reader;
mod line_assembler;
mod low_pass;
mod pipeline;
mod sync;
mod utils;

const SAMPLE_RATE: f32 = 20_000_000.0;
const SYNC_THRESHOLD: f32 = -0.4;
const LOWPASS_ALPHA: f32 = 0.7;

fn main() {
    // fn main() {
    let taps: [f32; 64] = [
        -0.00015813,
        -0.00047836,
        -0.00080166,
        -0.00110309,
        -0.00132172,
        -0.00136203,
        -0.00111203,
        -0.00047680,
        0.00057973,
        0.00199526,
        0.00358456,
        0.00504093,
        0.00597041,
        0.00595859,
        0.00466189,
        0.00190795,
        -0.00221520,
        -0.00730261,
        -0.01262639,
        -0.01719077,
        -0.01984753,
        -0.01945971,
        -0.01509023,
        -0.00618502,
        0.00728221,
        0.02473253,
        0.04499119,
        0.06638976,
        0.08695132,
        0.10463402,
        0.11759778,
        0.12445312,
        0.12445312,
        0.11759778,
        0.10463402,
        0.08695132,
        0.06638976,
        0.04499119,
        0.02473253,
        0.00728221,
        -0.00618502,
        -0.01509023,
        -0.01945971,
        -0.01984753,
        -0.01719077,
        -0.01262639,
        -0.00730261,
        -0.00221520,
        0.00190795,
        0.00466189,
        0.00595859,
        0.00597041,
        0.00504093,
        0.00358456,
        0.00199526,
        0.00057973,
        -0.00047680,
        -0.00111203,
        -0.00136203,
        -0.00132172,
        -0.00110309,
        -0.00080166,
        -0.00047836,
        -0.00015813,
    ];

    let source = FileSource::new("test.iq", 32769).unwrap();
    let samples: Vec<f32> = source
        .skip(10_000)
        .take(10_000)
        .agc(SAMPLE_RATE, 1.0, 0.001, 100.0)
        // .fir(taps, 1)
        .demodulate()
        .dc_block(0.997)
        .lowpass(LOWPASS_ALPHA)
        .filter_map(|r| r.ok())
        .collect();

    let min = samples.iter().cloned().fold(f32::INFINITY, f32::min);
    let max = samples.iter().cloned().fold(f32::NEG_INFINITY, f32::max);
    let mean: f32 = samples.iter().sum::<f32>() / samples.len() as f32;

    println!("min={:.3} max={:.3} mean={:.3}", min, max, mean);

    let source = FileSource::new("test.iq", 32769).unwrap();

    let frames: Vec<_> = source
        .skip(10_000)
        .take(5_000_000)
        .progress()
        .agc(SAMPLE_RATE, 1.0, 0.001, 100.0)
        // .fir(taps, 1)
        .demodulate()
        .dc_block(0.997)
        .lowpass(LOWPASS_ALPHA)
        .sync_separate(SAMPLE_RATE, SYNC_THRESHOLD)
        .assemble_frames()
        .filter_map(|r| r.ok())
        .collect();

    println!("{} frames decoded", frames.len());

    frame::save_frames(&frames, "frames", min, max);

    let source = FileSource::new("test.iq", 32769).unwrap();
    let samples: Vec<Sample> = source
        .skip(40_000)
        .take(1_000_000)
        .progress()
        .agc(20_000_000.0, 1.0, 0.001, 100.0)
        // .fir::<64>(taps, 1)
        .demodulate()
        .dc_block(0.997)
        .lowpass(0.75)
        .filter_map(|r| r.ok())
        .collect();

    let source = FileSource::new("test.iq", 32769).unwrap();
    let sync_events: Vec<(usize, &str)> = {
        use crate::sync::SyncEvent;
        let mut events = Vec::new();

        let source = FileSource::new("test.iq", 32769).unwrap();
        let mut separator = source
            .progress()
            .skip(40_000)
            .take(1_000_000)
            .agc(SAMPLE_RATE, 1.0, 0.001, 100.0)
            .demodulate()
            .dc_block(0.997)
            .lowpass(LOWPASS_ALPHA)
            .sync_separate(SAMPLE_RATE, SYNC_THRESHOLD);

        while let Some(r) = separator.next() {
            if let Ok(evt) = r {
                let pos = separator.samples_consumed;
                match evt {
                    SyncEvent::HSync => events.push((pos, "h")),
                    SyncEvent::VSync => {
                        events.push((pos, "v"));
                        println!("vsync\n")
                    }
                    SyncEvent::VideoSample(_) => {}
                }
            }
        }
        events
    };

    let _ = eframe::run_native(
        "DSP debug",
        Default::default(),
        Box::new(move |_cc| {
            Ok(Box::new(DebugApp {
                samples,
                sync_events,
            }))
        }),
    );

    // let _ = eframe::run_ui_native("DSP", Default::default(), move |ui, _frame| {
    //     egui::CentralPanel::default().show(ui, |ui| {
    //         Plot::new("plot").show(ui, |plot_ui| {
    //             plot_ui.line(Line::new(
    //                 "Signal",
    //                 samples
    //                     .iter()
    //                     .take(10000)
    //                     .enumerate()
    //                     .map(|(i, x)| [i as f64, *x as f64])
    //                     .collect::<Vec<_>>(),
    //             ))
    //         })
    //     });
    // });
}

struct DebugApp {
    samples: Vec<Sample>,
    sync_events: Vec<(usize, &'static str)>,
}

impl eframe::App for DebugApp {
    fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
        Plot::new("plot").show(ui, |plot_ui| {
            plot_ui.line(Line::new(
                "Signal",
                self.samples
                    .iter()
                    .enumerate()
                    .map(|(i, x)| [i as f64, *x as f64])
                    .collect::<Vec<_>>(),
            ));

            plot_ui.hline(
                HLine::new("Threshold", SYNC_THRESHOLD as f64)
                    .color(egui::Color32::YELLOW)
                    .width(4.0),
            );

            for (pos, kind) in &self.sync_events {
                let x = *pos as f64;
                match *kind {
                    "h" => plot_ui.vline(
                        VLine::new("HSync", x)
                            .color(egui::Color32::from_rgb(80, 160, 255))
                            .width(4.0),
                    ),
                    "v" => plot_ui.vline(
                        VLine::new("VSync", x)
                            .color(egui::Color32::BROWN)
                            .width(10.0),
                    ),
                    _ => {}
                }
            }
        });
    }
}
