#![windows_subsystem = "windows"]

use bitsy_parser::game::Game;
use gio::prelude::*;
use gtk::prelude::*;
use gtk::Orientation;
use std::env::args;

const SPACING: i32 = 16;

fn error_popup(message: &str) {
    let popup = gtk::Window::new(gtk::WindowType::Toplevel);
    popup.set_title("error");
    popup.set_border_width(SPACING as u32);
    popup.set_position(gtk::WindowPosition::Center);
    popup.set_default_size(256, 64);

    let vertical = gtk::Box::new(Orientation::Vertical, SPACING);
    popup.add(&vertical);

    let message = gtk::Label::new(Some(message));
    vertical.add(&message);

    let button_ok = gtk::Button::with_label("OK");
    vertical.add(&button_ok);

    popup.show_all();

    button_ok.connect_clicked(move |_| unsafe {
        popup.destroy();
    });
}

fn add_text_box(container: &gtk::Box, label: &str) -> gtk::TextBuffer {
    let vertical = gtk::Box::new(Orientation::Vertical, SPACING);
    vertical.set_property_expand(true);

    let label = gtk::Label::new(Some(label));
    vertical.add(&label);

    let h: Option<&gtk::Adjustment> = None;
    let v: Option<&gtk::Adjustment> = None;
    let scrolled_window = gtk::ScrolledWindow::new(h, v);
    scrolled_window.set_property_expand(true);
    let text_view = gtk::TextView::new();
    text_view.set_property_monospace(true);
    scrolled_window.add(&text_view);
    vertical.add(&scrolled_window);

    container.add(&vertical);

    text_view.get_buffer().unwrap()
}

fn parse_or_error(game_data: String, label: &str) -> Result<Game, ()> {
    let main = Game::from(game_data);
    if main.is_ok() {
        Ok(main.unwrap())
    } else {
        error_popup(&format!(
            "Couldn't parse {} game data: {:?}",
            label,
            main.unwrap_err()));
        Err(())
    }
}

fn buffer_to_string(buffer: &gtk::TextBuffer) -> String {
    let (start, end) = &buffer.get_bounds();
    buffer.get_text(start, end, false).unwrap().to_string()
}

fn build_ui(application: &gtk::Application) {
    let window = gtk::ApplicationWindow::new(application);

    window.set_title("mixsy");
    window.set_border_width(SPACING as u32);
    window.set_position(gtk::WindowPosition::Center);
    window.set_default_size(396, 512);

    let vertical = gtk::Box::new(Orientation::Vertical, SPACING);

    let buffer_main = add_text_box(&vertical, "main game data");
    let buffer_additional = add_text_box(&vertical, "additional game data");

    let button = gtk::Button::with_label("mix!");
    vertical.add(&button);

    let separator = gtk::Separator::new(Orientation::Vertical);
    vertical.add(&separator);

    let buffer_output = add_text_box(&vertical, "output");

    button.connect_clicked(move |_| {
        let main = buffer_to_string(&buffer_main);
        let additional = buffer_to_string(&buffer_additional);

        let main       = parse_or_error(main, "main");
        let additional = parse_or_error(additional, "additional");

        if main.is_ok() && additional.is_ok() {
            let mut main = main.unwrap();
            let additional = additional.unwrap();
            main.merge(additional);

            buffer_output.set_text(&main.to_string());
        }
    });

    window.add(&vertical);
    window.show_all();
}

fn main() {
    let application = gtk::Application::new(
        Some("dev.tinybird.max.mixsy-gtk"),
        Default::default()
    ).expect("Initialization failed...");

    application.connect_activate(|app| {
        build_ui(app);
    });

    application.run(&args().collect::<Vec<_>>());
}