use eframe::egui;
use json::JsonValue;
use std::io::{self, BufRead};
use std::sync::mpsc::{sync_channel, Receiver};
use std::thread;

fn main() -> Result<(), eframe::Error> {
    eframe::run_native(
        "Grazer",
        eframe::NativeOptions {
            initial_window_size: Some(egui::vec2(480.0, 360.0)),
            ..Default::default()
        },
        Box::new(|_cc| Box::<MyApp>::default()),
    )
}

struct MyApp {
    address: String,
    recv: Option<Receiver<JsonValue>>,
    last: JsonValue,
}

impl Default for MyApp {
    fn default() -> Self {
        Self {
            address: "about:grazer".to_owned(),
            last: json::parse("[[\"h1\",[],[\"Where would you like to graze today?\"]], [\"p\",[],[\"\"]], [\"p\",[],[\"🌱👩‍🌿🌾🌿🌷🌸🌱💮🍊🌾🌸🌱🍅🐌🍆🌲🌹🍃🌾🐌🍇🌱🍓🌲💚🌼\"]]]").unwrap(),
            recv: None,
        }
    }
}

impl MyApp {
    fn maybe_start(&mut self, ctx: &egui::Context) {
        if self.recv.is_none() {
            let ctx_clone = ctx.clone();
            let (sync_sender, receiver) = sync_channel(2);
            self.recv = Some(receiver);
            thread::spawn(move || {
                for l in io::stdin().lock().lines().map(|l| l.unwrap()) {
                    //eprintln!("Rust got {}", l);
                    sync_sender
                        .send(json::parse(&l).expect("Invalid JSON"))
                        .expect("Failed to send");
                    ctx_clone.request_repaint();
                }
                std::process::exit(0);
            });
        }
    }

    fn walk_dom(&mut self, dom: &json::JsonValue, ui: &mut egui::Ui) {
        use json::JsonValue::*;
        match dom {
            Short(s) => {
                ui.label(s.as_str().replace("\n", " "));
            }
            String(s) => {
                ui.label(s.as_str().replace("\n", " "));
            }
            Array(vec) => {
                if vec.len() == 3 && vec[0].is_string() {
                    match vec[0].as_str().unwrap() {
                        "head" | "script" | "style" | "comment" => {}
                        "h1" => {
                            ui.heading(vec[2][0].as_str().expect("text in h1"));
                        }
                        "a" => {
                            if ui.link(vec[2][0].as_str().expect("text in a")).clicked() {
                                vec[1]["href"].as_str().and_then(|href| {
                                    println!("navigate {}", href);
                                    self.address = href.to_owned();
                                    Some(())
                                });
                            }
                        }
                        "p" => {
                            //ui.style_mut().spacing.interact_size.y = 0.0;
                            ui.horizontal_wrapped(|ui| {
                                ui.spacing_mut().item_spacing.x = 0.0;
                                for val in vec[2].members() {
                                    self.walk_dom(val, ui)
                                }
                            });
                        }
                        s => {
                            for val in vec[2].members() {
                                self.walk_dom(val, ui)
                            }
                        }
                    }
                } else {
                    for val in vec {
                        self.walk_dom(val, ui)
                    }
                }
            }
            _ => panic!("Unexpected {:?}", dom),
        };
    }
}

impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        self.maybe_start(ctx);
        loop {
            match self.recv.as_mut().unwrap().try_recv() {
                Ok(line) => self.last = line,
                Err(_) => break,
            };
        }
        egui::TopBottomPanel::top("my_panel")
            //.frame(egui::containers::Frame::none()
            //       .inner_margin(egui::style::Margin::same(10.0)))
            .show(ctx, |ui| {
                ui.horizontal(|ui| {
                    let address_label = ui.label("🌍");
                    let response = ui
                        .text_edit_singleline(&mut self.address)
                        .labelled_by(address_label.id);
                    if response.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) {
                        println!("navigate {}", self.address);
                    }
                    if ui.button("Graze").clicked() {
                        println!("navigate {}", self.address);
                    }
                });
            });
        egui::CentralPanel::default().show(ctx, |ui| {
            egui::ScrollArea::vertical().show(ui, |ui| {
                self.walk_dom(&self.last.clone(), ui);
            });
        });
    }
}