#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

use crossbeam_channel::{unbounded, Receiver, Sender};
use eframe::egui;
use serialport::SerialPort;
use std::io::{BufRead, BufReader, Write};
use std::time::Duration;

struct SerialManager {
    port: Option<Box<dyn SerialPort>>,
    tx: Sender<String>,
    rx: Receiver<String>,
    is_connected: bool,
}

impl SerialManager {
    fn new() -> (Self, Sender<String>, Receiver<String>) {
        let (cmd_tx, cmd_rx) = unbounded::<String>();
        let (resp_tx, resp_rx) = unbounded::<String>();

        (
            Self {
                port: None,
                tx: resp_tx,
                rx: cmd_rx,
                is_connected: false,
            },
            cmd_tx,
            resp_rx,
        )
    }
}

struct WaveformApp {
    available_ports: Vec<String>,
    selected_port: String,
    freq: u32,
    log: Vec<String>,
    cmd_tx: Sender<String>,
    resp_rx: Receiver<String>,
    connected: bool,
}

impl Default for WaveformApp {
    fn default() -> Self {
        let (manager, cmd_tx, resp_rx) = SerialManager::new();

        // Spawn serial thread
        std::thread::spawn(move || {
            let mut m = manager;
            loop {
                if let Ok(cmd) = m.rx.try_recv() {
                    if cmd.starts_with("CONNECT:") {
                        let port_name = cmd.replace("CONNECT:", "");
                        match serialport::new(&port_name, 115200)
                            .timeout(Duration::from_millis(100))
                            .open()
                        {
                            Ok(p) => {
                                m.port = Some(p);
                                m.is_connected = true;
                                let _ = m.tx.send("STATUS:Connected".to_string());
                            }
                            Err(e) => {
                                let _ = m.tx.send(format!("ERR:{}", e));
                            }
                        }
                    } else if cmd == "DISCONNECT" {
                        m.port = None;
                        m.is_connected = false;
                        let _ = m.tx.send("STATUS:Disconnected".to_string());
                    } else if let Some(ref mut p) = m.port {
                        let _ = p.write_all(format!("{}\n", cmd).as_bytes());
                        let _ = p.flush();
                    }
                }

                if m.is_connected {
                    if let Some(ref mut p) = m.port {
                        let mut reader = BufReader::new(p);
                        let mut line = String::new();
                        if let Ok(_) = reader.read_line(&mut line) {
                            if !line.is_empty() {
                                let _ = m.tx.send(format!("ESP:{}", line.trim()));
                            }
                        }
                    }
                }
                std::thread::sleep(Duration::from_millis(10));
            }
        });

        Self {
            available_ports: vec![],
            selected_port: String::new(),
            freq: 100,
            log: vec!["Welcome. Select a port and click Connect.".to_string()],
            cmd_tx,
            resp_rx,
            connected: false,
        }
    }
}

impl eframe::App for WaveformApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        while let Ok(resp) = self.resp_rx.try_recv() {
            if resp == "STATUS:Connected" {
                self.connected = true;
            } else if resp == "STATUS:Disconnected" {
                self.connected = false;
            }
            self.log.push(resp);
            if self.log.len() > 100 {
                self.log.remove(0);
            }
        }

        egui::CentralPanel::default().show(ctx, |ui| {
            ui.vertical_centered(|ui| {
                ui.heading("ESP32-P4 Waveform Controller");
            });

            ui.add_space(10.0);

            // Connection Section
            ui.group(|ui| {
                ui.set_min_width(ui.available_width());
                ui.horizontal(|ui| {
                    if ui.button("🔄 Refresh").clicked() {
                        if let Ok(ports) = serialport::available_ports() {
                            self.available_ports = ports.into_iter().map(|p| p.port_name).collect();
                        }
                    }

                    egui::ComboBox::from_id_source("port_select")
                        .width(ui.available_width() - 120.0)
                        .selected_text(&self.selected_port)
                        .show_ui(ui, |ui| {
                            for port in &self.available_ports {
                                ui.selectable_value(&mut self.selected_port, port.clone(), port);
                            }
                        });

                    if !self.connected {
                        if ui
                            .add_sized([80.0, 20.0], egui::Button::new("Connect"))
                            .clicked()
                            && !self.selected_port.is_empty()
                        {
                            let _ = self.cmd_tx.send(format!("CONNECT:{}", self.selected_port));
                        }
                    } else {
                        if ui
                            .add_sized(
                                [80.0, 20.0],
                                egui::Button::new("Disconnect")
                                    .fill(egui::Color32::from_rgb(200, 50, 50)),
                            )
                            .clicked()
                        {
                            let _ = self.cmd_tx.send("DISCONNECT".to_string());
                        }
                    }
                });
            });

            ui.add_space(10.0);

            // System State - Fixed height group
            ui.group(|ui| {
                ui.set_min_width(ui.available_width());
                // We don't call ui.available_height() here to let it shrink to contents
                ui.horizontal(|ui| {
                    ui.set_enabled(self.connected);
                    let spacing = ui.spacing().item_spacing.x;
                    let btn_width = (ui.available_width() - (spacing * 2.0)) / 3.0;

                    if ui
                        .add_sized([btn_width, 30.0], egui::Button::new("✅ ENABLE Stage"))
                        .clicked()
                    {
                        let _ = self.cmd_tx.send("ENABLE".to_string());
                    }
                    if ui
                        .add_sized([btn_width, 30.0], egui::Button::new("❌ DISABLE Stage"))
                        .clicked()
                    {
                        let _ = self.cmd_tx.send("DISABLE".to_string());
                    }
                    if ui
                        .add_sized([btn_width, 30.0], egui::Button::new("📡 PING"))
                        .clicked()
                    {
                        let _ = self.cmd_tx.send("PING".to_string());
                    }
                });
            });

            ui.add_space(10.0);

            // Manual Control
            ui.group(|ui| {
                ui.set_min_width(ui.available_width());
                ui.label(
                    egui::RichText::new("Manual Control (Reversed: ON=A0/B1, OFF=A1/B0)").strong(),
                );
                ui.horizontal(|ui| {
                    ui.set_enabled(self.connected);
                    let spacing = ui.spacing().item_spacing.x;
                    let btn_width = (ui.available_width() - spacing) / 4.0;
                    if ui
                        .add_sized([btn_width, 25.0], egui::Button::new("ON"))
                        .clicked()
                    {
                        let _ = self.cmd_tx.send("ON".to_string());
                    }
                    if ui
                        .add_sized([btn_width, 25.0], egui::Button::new("OFF"))
                        .clicked()
                    {
                        let _ = self.cmd_tx.send("OFF".to_string());
                    }
                    if ui
                        .add_sized([btn_width, 25.0], egui::Button::new("ALL ON"))
                        .clicked()
                    {
                        let _ = self.cmd_tx.send("ALL_ON".to_string());
                    }
                    if ui
                        .add_sized([btn_width, 25.0], egui::Button::new("ALL OFF"))
                        .clicked()
                    {
                        let _ = self.cmd_tx.send("ALL_OFF".to_string());
                    }
                });
            });

            ui.add_space(10.0);

            // Modulation Control
            ui.group(|ui| {
                ui.set_min_width(ui.available_width());
                ui.label(egui::RichText::new("Modulation Control").strong());

                ui.add_space(5.0);
                ui.horizontal(|ui| {
                    ui.set_enabled(self.connected);
                    ui.add(
                        egui::Slider::new(&mut self.freq, 10..=5000)
                            .text("Hz")
                            .trailing_fill(true),
                    );

                    if ui.button("Set Frequency").clicked() {
                        let _ = self.cmd_tx.send(format!("F {}", self.freq));
                    }
                });

                ui.add_space(5.0);
                ui.horizontal(|ui| {
                    ui.set_enabled(self.connected);
                    let spacing = ui.spacing().item_spacing.x;
                    let btn_width = (ui.available_width() - spacing) / 2.0;
                    if ui
                        .add_sized([btn_width, 30.0], egui::Button::new("▶ START MOD"))
                        .clicked()
                    {
                        let _ = self.cmd_tx.send("MOD_ON".to_string());
                    }
                    if ui
                        .add_sized([btn_width, 30.0], egui::Button::new("⏹ STOP MOD"))
                        .clicked()
                    {
                        let _ = self.cmd_tx.send("MOD_OFF".to_string());
                    }
                });
            });

            ui.add_space(10.0);

            // Log Section
            ui.label("Terminal Log:");
            egui::Frame::none()
                .fill(egui::Color32::from_black_alpha(240))
                .rounding(4.0)
                .show(ui, |ui| {
                    ui.set_min_width(ui.available_width());
                    egui::ScrollArea::vertical()
                        .max_height(f32::INFINITY)
                        .auto_shrink([false, false])
                        .stick_to_bottom(true)
                        .show(ui, |ui| {
                            for line in &self.log {
                                let color = if line.starts_with("ERR") {
                                    egui::Color32::LIGHT_RED
                                } else if line.starts_with("STATUS") {
                                    egui::Color32::LIGHT_BLUE
                                } else {
                                    egui::Color32::LIGHT_GRAY
                                };
                                ui.label(egui::RichText::new(line).color(color).monospace());
                            }
                        });
                });
        });

        ctx.request_repaint_after(Duration::from_millis(50));
    }
}

fn main() -> eframe::Result<()> {
    let options = eframe::NativeOptions {
        viewport: egui::ViewportBuilder::default()
            .with_inner_size([600.0, 650.0])
            .with_min_inner_size([400.0, 500.0]),
        ..Default::default()
    };
    eframe::run_native(
        "ESP32-P4 Waveform Gen",
        options,
        Box::new(|_cc| Box::new(WaveformApp::default())),
    )
}
