use roast2d::prelude::*;
use std::fs;
use std::sync::{Arc, Mutex};

struct ShowcaseState {
    counter: i32,
    slider_value: f32,
    checkbox_enabled: bool,
    radio_choice: i32,
    combo_index: usize,
    singleline_text: String,
    multiline_text: String,
    color: egui::Color32,
    progress: f32,
}

impl Default for ShowcaseState {
    fn default() -> Self {
        Self {
            counter: 0,
            slider_value: 0.5,
            checkbox_enabled: true,
            radio_choice: 0,
            combo_index: 0,
            singleline_text: "Hello egui".to_string(),
            multiline_text: "This is a multi-line text box.\nYou can type here.".to_string(),
            color: egui::Color32::from_rgb(120, 200, 100),
            progress: 0.2,
        }
    }
}

struct EguiShowcase {
    state: Arc<Mutex<ShowcaseState>>,
}

impl Default for EguiShowcase {
    fn default() -> Self {
        Self {
            state: Arc::new(Mutex::new(ShowcaseState::default())),
        }
    }
}

fn load_system_cjk_font() -> Option<Vec<u8>> {
    #[cfg(target_os = "macos")]
    const CANDIDATES: &[&str] = &[
        "/System/Library/Fonts/PingFang.ttc",
        "/System/Library/Fonts/STHeiti Medium.ttc",
    ];

    #[cfg(target_os = "windows")]
    const CANDIDATES: &[&str] = &[
        "C:\\Windows\\Fonts\\msyh.ttc",
        "C:\\Windows\\Fonts\\msyh.ttf",
        "C:\\Windows\\Fonts\\simhei.ttf",
    ];

    #[cfg(target_os = "linux")]
    const CANDIDATES: &[&str] = &[
        "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
        "/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
    ];

    #[allow(unused)]
    const EMPTY: &[&str] = &[];

    #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
    let candidates: &[&str] = EMPTY;
    #[cfg(any(target_os = "macos", target_os = "windows", target_os = "linux"))]
    let candidates: &[&str] = CANDIDATES;

    for path in candidates {
        if let Ok(bytes) = fs::read(path) {
            return Some(bytes);
        }
    }
    None
}

fn setup_cjk_fonts(ctx: &egui::Context) {
    use egui::{FontData, FontDefinitions, FontFamily};

    let Some(bytes) = load_system_cjk_font() else {
        log::warn!("No system CJK font found; egui will show tofu for CJK");
        return;
    };

    let mut fonts = FontDefinitions::default();
    fonts
        .font_data
        .insert("cjk".to_owned(), FontData::from_owned(bytes).into());

    fonts
        .families
        .entry(FontFamily::Proportional)
        .or_default()
        .insert(0, "cjk".to_owned());
    fonts
        .families
        .entry(FontFamily::Monospace)
        .or_default()
        .insert(0, "cjk".to_owned());

    ctx.set_fonts(fonts);
}

impl Scene for EguiShowcase {
    fn init(&mut self, g: &mut Engine) {
        g.egui(|ctx, _g| {
            setup_cjk_fonts(ctx);
        });
    }

    fn update(&mut self, g: &mut Engine) {
        let dt = g.tick;
        if let Ok(mut state) = self.state.lock() {
            state.progress = (state.progress + dt * 0.1).fract();
        }
    }

    fn draw(&mut self, g: &mut Engine) {
        let state = self.state.clone();

        g.egui(move |ctx, _g| {
            let mut state = match state.lock() {
                Ok(s) => s,
                Err(poisoned) => poisoned.into_inner(),
            };

            egui::TopBottomPanel::top("top_bar").show(ctx, |ui| {
                egui::MenuBar::new().ui(ui, |ui| {
                    ui.menu_button("File", |ui| {
                        if ui.button("New").clicked() {
                            state.counter = 0;
                            ui.close();
                        }
                        if ui.button("Quit").clicked() {
                            ui.close();
                        }
                    });
                    ui.menu_button("View", |ui| {
                        ui.label("Toggle things in the side panel.");
                    });
                });
            });

            egui::SidePanel::left("side_panel")
                .resizable(true)
                .show(ctx, |ui| {
                    ui.heading("Controls");

                    if ui.button("Increment counter").clicked() {
                        state.counter += 1;
                    }
                    ui.label(format!("Counter: {}", state.counter));

                    ui.separator();

                    ui.label("Checkbox:");
                    ui.checkbox(&mut state.checkbox_enabled, "Enable something");

                    ui.label("Radio buttons:");
                    ui.radio_value(&mut state.radio_choice, 0, "Option A");
                    ui.radio_value(&mut state.radio_choice, 1, "Option B");
                    ui.radio_value(&mut state.radio_choice, 2, "Option C");

                    ui.separator();

                    ui.label("Combo box:");
                    let items = ["Apple", "Banana", "Orange", "Grape"];
                    egui::ComboBox::from_label("Fruits")
                        .selected_text(*items.get(state.combo_index).unwrap_or(&"Unknown"))
                        .show_ui(ui, |ui| {
                            for (i, item) in items.iter().enumerate() {
                                if ui.selectable_label(state.combo_index == i, *item).clicked() {
                                    state.combo_index = i;
                                }
                            }
                        });
                });

            egui::CentralPanel::default().show(ctx, |ui| {
                ui.heading("Egui Showcase");

                ui.horizontal(|ui| {
                    ui.label("Slider:");
                    ui.add(
                        egui::Slider::new(&mut state.slider_value, 0.0..=1.0)
                            .show_value(true)
                            .text("value"),
                    );
                });

                ui.horizontal(|ui| {
                    ui.label("Drag value:");
                    ui.add(egui::DragValue::new(&mut state.counter).speed(1));
                });

                ui.separator();

                ui.label("Single-line text:");
                ui.text_edit_singleline(&mut state.singleline_text);

                ui.label("Multi-line text:");
                ui.add(
                    egui::TextEdit::multiline(&mut state.multiline_text)
                        .desired_rows(4)
                        .lock_focus(true),
                );

                ui.separator();

                ui.horizontal(|ui| {
                    ui.label("Color:");
                    ui.color_edit_button_srgba(&mut state.color);
                });

                ui.add(
                    egui::widgets::ProgressBar::new(state.progress)
                        .text(format!("{:.0}%", state.progress * 100.0)),
                );

                ui.separator();

                egui::CollapsingHeader::new("Scrollable list")
                    .default_open(false)
                    .show(ui, |ui| {
                        egui::ScrollArea::vertical()
                            .max_height(200.0)
                            .show(ui, |ui| {
                                for i in 0..50 {
                                    ui.label(format!("Item #{i}"));
                                }
                            });
                    });

                egui::CollapsingHeader::new("Tree structure")
                    .default_open(false)
                    .show(ui, |ui| {
                        egui::CollapsingHeader::new("Parent A").show(ui, |ui| {
                            ui.label("Child A1");
                            ui.label("Child A2");
                        });
                        egui::CollapsingHeader::new("Parent B").show(ui, |ui| {
                            ui.label("Child B1");
                            ui.label("Child B2");
                        });
                    });
            });
        });
    }
}

fn setup(g: &mut Engine) {
    g.set_scale_mode(ScaleMode::Fixed {
        width: 1280,
        height: 720,
    });
    g.set_scene(EguiShowcase::default());
}

fn main() {
    env_logger::init();
    let app = App::default()
        .title("Egui Showcase".to_string())
        .window(UVec2::new(1280, 720))
        .vsync(true)
        .resizable(true);
    app.run(setup).expect("Start game");
}
