// SPDX-License-Identifier: GPL-3.0-or-later

//! The text area component

use glib::{Cast, CastNone};
use grx_macros::{gtk_component, props};
use gtk::glib;
use gtk::traits::TextBufferExt;
use gtk::traits::TextViewExt;
use gtk::traits::WidgetExt;
use std::rc::Rc;

use crate::{default_on_click, default_on_swipe, handlers::Handler, new_gc, Interactable, Textual};

use super::gtk_props::apply;

#[props]
#[derive(Default)]
pub struct Props {
    pub on_change: Option<Handler<TextArea>>,
    pub on_blur: Option<Handler<TextArea>>,
    pub password: Option<bool>,
    pub disabled: bool,
}

impl std::fmt::Debug for Props {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Props")
            .field("id", &self.id)
            .field("classes", &self.classes)
            .field("styles", &self.styles)
            .field("children", &self.children)
            .field("on_change", &self.on_change.is_some())
            .field("on_blur", &self.on_blur.is_some())
            .field("password", &self.password)
            .field("disabled", &self.disabled)
            .finish()
    }
}

pub fn text_area(mut props: Props) -> Rc<TextArea> {
    let text_area: gtk::TextView = gtk::TextView::builder().build();
    let on_blur = props.on_blur.take();
    let on_change = props.on_change.take();

    text_area.set_sensitive(!props.disabled);

    let w = text_area.clone();
    let component = new_gc!(TextArea { w, props });

    apply(component.clone());

    if let Some(onc) = on_change {
        let comp = component.clone();
        text_area.connect_buffer_notify(move |_| {
            onc(comp.clone());
        });
    }

    if let Some(onb) = on_blur {
        let comp = component.clone();
        if let Some(text) = text_area.first_child().and_downcast_ref::<gtk::Text>() {
            text.connect_has_focus_notify(move |w| {
                if !w.has_focus() {
                    onb(comp.clone())
                }
            });
        }
    }

    component
}

#[gtk_component(gtk::TextView)]
#[derive(Debug)]
pub struct TextArea {}

impl Interactable for TextArea {
    default_on_click! {}
    default_on_swipe! {}

    fn on_change(self: &Rc<Self>, handler: impl Fn(&Rc<Self>) + 'static) {
        let s = self.clone();
        self.widget.connect_buffer_notify(move |_| handler(&s));
        // TextViewExt::connect
    }

    fn on_blur(self: &Rc<Self>, handler: impl Fn(&Rc<Self>) + 'static) {
        let s = self.clone();
        if let Some(text) = self.widget.first_child().and_downcast_ref::<gtk::Text>() {
            text.connect_has_focus_notify(move |w| {
                if !w.has_focus() {
                    handler(&s)
                }
            });
        }
    }
}

impl Textual for TextArea {
    fn text(self: &Rc<Self>) -> String {
        self.widget.buffer().to_string()
    }

    fn set_text(self: &Rc<Self>, text: &str) {
        self.widget.buffer().set_text(text)
    }
}
