#![no_std]

use esp_hal::Async;
use esp_hal::gpio::Level;
use esp_hal::rmt::{Channel, PulseCode, Tx};
use heapless::Vec;
use smart_leds::RGB8;

const fn ns_to_ticks(ns: u32) -> u16 {
    ((ns + 6) / 12) as u16
}

const T0H: u16 = ns_to_ticks(350);
const T0L: u16 = ns_to_ticks(800);
const T1H: u16 = ns_to_ticks(700);
const T1L: u16 = ns_to_ticks(600);
const RESET: u16 = ns_to_ticks(50_000);

fn encode_byte(byte: u8) -> [PulseCode; 8] {
    let mut items = [PulseCode::new(Level::High, T0H, Level::Low, T0L); 8];
    for i in 0..8 {
        items[i] = if (byte >> (7 - i)) & 1 != 0 {
            PulseCode::new(Level::High, T1H, Level::Low, T1L)
        } else {
            PulseCode::new(Level::High, T0H, Level::Low, T0L)
        };
    }
    items
}

fn encode_color(color: RGB8) -> [PulseCode; 24] {
    let mut items = [PulseCode::new(Level::High, T0H, Level::Low, T0L); 24];
    items[0..8].copy_from_slice(&encode_byte(color.g));
    items[8..16].copy_from_slice(&encode_byte(color.r));
    items[16..24].copy_from_slice(&encode_byte(color.b));
    items
}

pub struct Ws2812<'a> {
    channel: Channel<'a, Async, Tx>,
}

impl<'a> Ws2812<'a> {
    pub fn new(channel: Channel<'a, Async, Tx>) -> Self {
        Self { channel }
    }

    pub async fn write(&mut self, colors: &[RGB8]) -> Result<(), esp_hal::rmt::Error> {
        let mut buffer: Vec<PulseCode, 6144> = Vec::new();

        for color in colors {
            for item in encode_color(*color) {
                buffer.push(item).ok();
            }
        }

        buffer
            .push(PulseCode::new(Level::Low, RESET, Level::Low, 0))
            .ok();
        buffer.push(PulseCode::end_marker()).ok();

        self.channel.transmit(&buffer).await
    }
}
