// src/bin/main.rs
#![no_std]
#![no_main]

use defmt::*;
use core::sync::atomic::{AtomicBool, Ordering};
use embassy_executor::Spawner;
use embassy_stm32::usart::{Config, Uart, UartRx, UartTx, InterruptHandler};
use embassy_stm32::peripherals::{USART1, USART3};
use embassy_stm32::bind_interrupts;
use embassy_time::{Duration, Timer};
use embassy_sync::channel::Channel;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;

use {defmt_rtt as _, panic_probe as _};

bind_interrupts!(struct Irqs {
    USART1 => InterruptHandler<USART1>;
    USART3 => InterruptHandler<USART3>;
});

static PIPE: Channel<CriticalSectionRawMutex, u8, 64> = Channel::new();
static SEND_ALLOWED: AtomicBool = AtomicBool::new(true);
static REC_ALLOWED: AtomicBool = AtomicBool::new(true);

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    info!("tititititi");

    let p = embassy_stm32::init(Default::default());

    let config = Config::default();
    let dev_usart = Uart::new(
        p.USART1,
        p.PA10,
        p.PA9,
        Irqs,
        p.GPDMA1_CH0, // TX DMA
        p.GPDMA1_CH1, // RX DMA
        config,
    ).unwrap();

    let uart = Uart::new(
        p.USART3,
        p.PD9, // RX zo zariadenia
        p.PD8, // TX do zariadenia
        Irqs,
        p.GPDMA1_CH2,
        p.GPDMA1_CH3,
        config,
    ).unwrap();
    let (mut tx, rx) = uart.split();
    let (dev_tx, dev_rx) = dev_usart.split();
    spawner.spawn(rx_task(rx, dev_tx)).unwrap();
    spawner.spawn(toggle_rec_task()).unwrap();

    let sender = PIPE.sender();
    let receiver = PIPE.receiver();

    info!("starting echo");

    let data = b"filip\r\n";
    let idle = &[0x13u8];

    loop {
        // rec_allowed = (start_time.elapsed().as_secs() / 2) % 2 == 0;
        let current_send_allowed = SEND_ALLOWED.load(Ordering::Relaxed);
        let current_rec_allowed = REC_ALLOWED.load(Ordering::Relaxed);
        if current_rec_allowed == true {
            if current_send_allowed {
                if let Ok(stored_byte) = receiver.try_receive() {
                    let _ = tx.write(&[stored_byte]).await;
                } else {
                    let _ = tx.write(data).await;
                }
            } else {
                for b in data {
                    let _ = sender.try_send(*b);
                }
            }
        } else {
            let _ = tx.write(idle).await;
        }
        let _ = Timer::after(Duration::from_millis(100));
    }
}

#[embassy_executor::task]
async fn rx_task(
    mut rx: UartRx<'static, embassy_stm32::mode::Async>,
    mut pc_tx: UartTx<'static, embassy_stm32::mode::Async>
) {
    let mut buf = [0u8; 1];
    loop {
        if rx.read(&mut buf).await.is_ok() {
            match buf[0] {
                0x11 => {
                    SEND_ALLOWED.store(true, Ordering::Relaxed);
                    info!("Vysielanie povolené");
                }
                0x13 => {
                    SEND_ALLOWED.store(false, Ordering::Relaxed);
                    info!("Vysielanie zakázané");
                }
                _ => {}
            }
            let _ = pc_tx.write(&buf).await;
        }
    }
}

#[embassy_executor::task]
async fn toggle_rec_task() {
    loop {
        Timer::after(Duration::from_secs(2)).await;
        // Načítame aktuálnu hodnotu a uložíme jej opak
        let current = REC_ALLOWED.load(Ordering::Relaxed);
        REC_ALLOWED.store(!current, Ordering::Relaxed);

        if !current {
            info!("REC_ALLOWED: true");
        } else {
            info!("REC_ALLOWED: false");
        }
    }
}
