use std::{
    f32::consts::PI,
    fs::File,
    io::{Read, Write},
    ops::{Add, Div, Mul, Sub},
};

mod bfsk;
mod complex;
pub mod fft;
mod nco;

use bfsk::BFSKMod;
use complex::Complex;
use complex::Complex32;
use fft::rader;
use nco::Nco;
use plotters::prelude::*;

use crate::bfsk::BFSKDem;

// Utilities
fn map<T>(input: T, in_min: T, in_max: T, out_min: T, out_max: T) -> T
where
    T: Clone + Add<Output = T> + Mul<Output = T> + Sub<Output = T> + Div<Output = T>,
{
    ((input - in_min.clone()) / (in_max - in_min)) * (out_max - out_min.clone()) + out_min
}

fn main() {
    modulate();
}

fn modulate() {
    let sample_rate = 44100;
    let mut frequency = 2000.0; //HZ
    let mut bandwidth = 500.0; //HZ

    let path = "s.txt";
    let file = File::open(path).unwrap();
    let mut bit_stream = file.bytes().flat_map(|byte| {
        let byte = byte.unwrap();
        [
            byte & 1 == 1,
            (byte >> 1) & 1 == 1,
            (byte >> 2) & 1 == 1,
            (byte >> 3) & 1 == 1,
            (byte >> 4) & 1 == 1,
            (byte >> 5) & 1 == 1,
            (byte >> 6) & 1 == 1,
            (byte >> 7) & 1 == 1,
        ]
    });
    //let mut bit_stream = (0..22000).map(|_| false).chain((0..22000).map(|_| true));
    //let mut bit_stream = (0..22000).flat_map(|_| [true, false]);

    let baud_rate = 400;
    println!("{} samples/bit", sample_rate / baud_rate);
    let mut bfsk = BFSKMod::new(
        sample_rate / baud_rate,
        2. * PI * (bandwidth / sample_rate as f32),
        &mut bit_stream,
    );

    let spec = hound::WavSpec {
        channels: 1,
        sample_rate,
        bits_per_sample: 16,
        sample_format: hound::SampleFormat::Int,
    };
    let mut writer = hound::WavWriter::create("sine.wav", spec).unwrap();

    let mut lo = Nco::new(2. * PI * (frequency / sample_rate as f32));

    let prev = Complex::new(0., 0.);
    let alpha = 1.0 - (-2.0 * PI * ((1.5 * 0.5 * bandwidth) / sample_rate as f32));
    let mut output_samples = vec![];
    while let Some(sample) = bfsk.step_modulate() {
        let amplitude = i16::MAX as f32;
        let c_sample = lo.cexp() * sample;

        let filtered = prev + (c_sample - prev) * alpha;
        output_samples.push(filtered);
        writer
            .write_sample((amplitude * c_sample.re) as i16)
            .unwrap();
        lo.step();
    }
    writer.finalize().unwrap();

    let mut of = File::create("out.txt").unwrap();

    let mut bits = vec![];
    let mut lodem = Nco::new(-2. * PI * (frequency / sample_rate as f32));
    let mut demod = BFSKDem::new(
        sample_rate / baud_rate,
        PI * (bandwidth / sample_rate as f32),
    );
    for chunk in output_samples.chunks((sample_rate / baud_rate) as usize) {
        let base_chunk: Vec<Complex32> = chunk
            .iter()
            .map(|x| {
                lodem.step();
                *x * lodem.cexp()
            })
            .collect();
        let bit = demod.demod(base_chunk.as_slice());
        bits.push(bit);
        println!("{:?}", bit)
    }

    for b in bits.chunks(8) {
        of.write_all(&[(b[0] as u8)
            | ((b[0] as u8) << 1)
            | ((b[0] as u8) << 2)
            | ((b[0] as u8) << 3)
            | ((b[0] as u8) << 4)
            | ((b[0] as u8) << 5)
            | ((b[0] as u8) << 6)
            | ((b[0] as u8) << 7)])
            .unwrap();
    }
}
