mod audio;
mod container;
mod figure;
mod image;
mod label;
mod list;
mod math;
mod quote;
mod sourceview;
mod table;
mod video;

use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::Arc;

use crate::elements::{Element, Label};
use crate::{ImageDownloaderExt, MathRendererExt, WidgetConfig};
use gtk4::Widget;

pub use audio::AudioWidget;
pub use image::{ImageType, ImageWidget};
pub use label::LabelWithWidgets;
pub use video::VideoWidget;

#[derive(Clone)]
pub struct WidgetBuilder {
    config: WidgetConfig,
    image_downloader: Option<Arc<Box<dyn ImageDownloaderExt>>>,
    math_renderer: Option<Arc<Box<dyn MathRendererExt>>>,
    id_map: Rc<RefCell<HashMap<String, Widget>>>,
    content_id: String,
    scale_factor: i32,
}

impl Default for WidgetBuilder {
    fn default() -> Self {
        Self {
            config: WidgetConfig::default(),
            image_downloader: None,
            math_renderer: None,
            id_map: Rc::new(RefCell::new(HashMap::new())),
            content_id: String::new(),
            scale_factor: 1,
        }
    }
}

impl WidgetBuilder {
    pub fn config(mut self, config: WidgetConfig) -> Self {
        self.config = config;
        self
    }

    pub fn content_id(mut self, content_id: String) -> Self {
        self.content_id = content_id;
        self
    }

    pub fn image_downloader(
        mut self,
        image_downloader: Option<&Arc<Box<dyn ImageDownloaderExt>>>,
    ) -> Self {
        self.image_downloader = image_downloader.cloned();
        self
    }

    pub fn math_renderer(mut self, math_renderer: Option<&Arc<Box<dyn MathRendererExt>>>) -> Self {
        self.math_renderer = math_renderer.cloned();
        self
    }

    pub fn id_map(mut self, id_map: Rc<RefCell<HashMap<String, Widget>>>) -> Self {
        self.id_map = id_map.clone();
        self
    }

    pub fn scale_factor(mut self, scale_factor: i32) -> Self {
        self.scale_factor = scale_factor;
        self
    }

    pub fn build(self, element: Element) -> Widget {
        self.build_element(element)
    }

    fn build_element(&self, element: Element) -> Widget {
        match element {
            Element::Label(label) => self.create_label(label),
            Element::Image(image) => self.create_image(image, ImageType::Single),
            Element::Gallery(images) => self.create_image_gallery(images),
            Element::Audio(audio) => self.create_audio(audio),
            Element::Video(video) => self.create_video(video),
            Element::List(list_items) => self.create_list(list_items),
            Element::Table(table) => self.create_table(table),
            Element::Container(elements) => self.create_box(elements),
            Element::Quote(element) => self.create_quote(*element),
            Element::Figure(figure) => self.create_figure(figure),
            Element::Code(source) => self.create_source_view(source),
            Element::Math(mathjax) => self.render_math(mathjax),
            Element::Paragraph(paragraph) => self.create_label(Label::from(paragraph)),
        }
    }
}
