use std::{
    borrow::BorrowMut,
    collections::VecDeque,
    ops::Add,
    time::{Duration, Instant},
};

use crate::ui::{
    main,
    status_bar::{self},
};
use eframe::{
    egui::{self, Direction},
    epaint::Pos2,
};
use egui_toast::{Toast, ToastKind, ToastOptions, Toasts};

pub struct MainWindow {
    pages: VecDeque<Box<dyn InterfacePage>>,
    curr_title: String,
    bar: Option<Box<dyn StatusBar>>,
    show_back: bool,
}

impl MainWindow {
    pub fn new() -> Self {
        Self {
            pages: VecDeque::new(),
            curr_title: "OpenVehicleDiag".into(),
            bar: None,
            show_back: true,
        }
    }
    pub fn add_new_page(&mut self, p: Box<dyn InterfacePage>) {
        if let Some(bar) = p.get_status_bar() {
            self.bar = Some(bar)
        }
        self.pages.push_front(p)
    }

    pub fn pop_page(&mut self) {
        self.pages.pop_front();
        if let Some(bar) = self.pages.get_mut(0).map(|x| x.get_status_bar()) {
            self.bar = bar
        }
    }
}

impl eframe::App for MainWindow {
    fn update(&mut self, ctx: &eframe::egui::Context, frame: &mut eframe::Frame) {
        let stack_size = self.pages.len();
        let mut s_bar_height = 0.0;
        if stack_size > 0 {
            let mut pop_page = false;
            if let Some(status_bar) = self.bar.borrow_mut() {
                egui::TopBottomPanel::bottom("NAV").show(ctx, |nav| {
                    nav.horizontal(|row| {
                        status_bar.draw(row, ctx);
                        if stack_size > 1 && self.show_back {
                            if row.button("Back").clicked() {
                                pop_page = true;
                            }
                        }
                    });
                    s_bar_height = nav.available_height()
                });
            }
            if pop_page {
                self.pop_page();
            }

            let mut toasts = Toasts::new(ctx)
                .anchor(Pos2::new(
                    5.0,
                    ctx.available_rect().height() - s_bar_height - 5.0,
                ))
                .align_to_end(false)
                .direction(Direction::BottomUp);

            egui::CentralPanel::default().show(ctx, |main_win_ui| {
                match self.pages[0].make_ui(main_win_ui, frame) {
                    PageAction::None => {}
                    PageAction::Destroy => self.pop_page(),
                    PageAction::Add(p) => self.add_new_page(p),
                    PageAction::Overwrite(p) => {
                        self.pages[0] = p;
                        self.bar = self.pages[0].get_status_bar();
                    }
                    PageAction::RePaint => ctx.request_repaint(),
                    PageAction::SetBackButtonState(state) => {
                        self.show_back = state;
                    }
                    PageAction::SendNotification { text, kind } => {
                        println!("Pushing notification {}", text);
                        toasts.add(
                            text,
                            kind,
                            ToastOptions {
                                show_icon: true,
                                expires_at: Some(Instant::now().add(Duration::from_secs(5))),
                            },
                        );
                    }
                }
            });
            toasts.show();
        }
        ctx.request_repaint();
    }
}

pub enum PageAction {
    None,
    Destroy,
    Add(Box<dyn InterfacePage>),
    Overwrite(Box<dyn InterfacePage>),
    SetBackButtonState(bool),
    RePaint,
    SendNotification { text: String, kind: ToastKind },
}

pub trait InterfacePage {
    fn make_ui(&mut self, ui: &mut egui::Ui, frame: &eframe::Frame) -> PageAction;
    fn get_title(&self) -> &'static str;
    fn get_status_bar(&self) -> Option<Box<dyn StatusBar>>;
}

pub trait StatusBar {
    fn draw(&mut self, ui: &mut egui::Ui, ctx: &egui::Context);
}
