use crate::elements::Audio;
use clapper_player::MediaItem;
use clapper_player_gtk::{Audio as ClapperAudio, prelude::*};
use gtk4::glib::{self, Object, Properties, subclass::prelude::*, subclass::*};
use gtk4::{
    Accessible, Buildable, CompositeTemplate, ConstraintTarget, Widget, prelude::*,
    subclass::prelude::*,
};
use libadwaita::{Bin, subclass::prelude::*};
use std::cell::RefCell;

mod imp {
    use super::*;

    #[derive(Debug, Default, CompositeTemplate, Properties)]
    #[properties(wrapper_type = super::AudioWidget)]
    #[template(file = "src/widget_factory/audio/widget.blp")]
    pub struct AudioWidget {
        #[template_child]
        pub audio: TemplateChild<ClapperAudio>,

        #[property(get, set, construct_only)]
        pub item: RefCell<MediaItem>,

        #[property(get, set, construct_only, nullable, name = "fallback-title")]
        pub fallback_title: RefCell<Option<String>>,
    }

    #[glib::object_subclass]
    impl ObjectSubclass for AudioWidget {
        const NAME: &'static str = "AudioWidget";
        type Type = super::AudioWidget;
        type ParentType = Bin;

        fn class_init(klass: &mut Self::Class) {
            klass.bind_template();
            klass.bind_template_callbacks();
        }

        fn instance_init(obj: &InitializingObject<Self>) {
            obj.init_template();
        }
    }

    #[glib::derived_properties]
    impl ObjectImpl for AudioWidget {
        fn constructed(&self) {
            let Some(player) = self.audio.player() else {
                return;
            };

            if let Some(queue) = player.queue() {
                queue.add_item(&self.item.borrow());
                queue.select_item(Some(&*self.item.borrow()));
            }
        }
    }

    impl WidgetImpl for AudioWidget {}

    impl BinImpl for AudioWidget {}

    #[gtk4::template_callbacks]
    impl AudioWidget {
        #[template_callback]
        fn fallback_title(&self, title: Option<String>) -> String {
            if let Some(title) = title {
                title
            } else if let Some(title) = self.obj().fallback_title() {
                title
            } else {
                "Audio Track".into()
            }
        }
    }
}

glib::wrapper! {
    pub struct AudioWidget(ObjectSubclass<imp::AudioWidget>)
        @extends Widget, Bin,
        @implements Accessible, Buildable, ConstraintTarget;
}

impl From<&Audio> for AudioWidget {
    fn from(value: &Audio) -> Self {
        let item = MediaItem::new(value.url.as_str());

        Object::builder()
            .property("item", item)
            .property("fallback-title", &value.title)
            .build()
    }
}
