//! Auto-generated safe bindings to LVGL functions

use ::core::{
    ffi::{CStr, c_void},
    time::Duration,
};

use log::Level;

use crate::styles::Style;
use crate::{
    events::Event,
    subjects::Subject,
    widgets::{Wdg, Widget},
};

pub fn lv_init() {
    unsafe {
        lightvgl_sys::lv_init();
    }
}

pub fn lv_tick_inc(diff: Duration) {
    unsafe { lightvgl_sys::lv_tick_inc(diff.as_millis() as u32) }
}

pub fn lv_tick_set_cb<F>(callback: F)
where
    F: FnMut() -> u32 + 'static,
{
    crate::timers::lv_tick_set_cb(callback);
}

pub fn lv_timer_handler() -> u32 {
    unsafe { lightvgl_sys::lv_timer_handler() }
}

pub fn lv_pct(pct: lightvgl_sys::lv_coord_t) -> lightvgl_sys::lv_coord_t {
    unsafe { lightvgl_sys::lv_pct(pct) }
}

pub fn lv_dpx(n: i32) -> i32 {
    unsafe { lightvgl_sys::lv_dpx(n) }
}

#[cfg(LV_USE_GRID)]
pub fn lv_grid_fr(x: u8) -> i32 {
    unsafe { lightvgl_sys::lv_grid_fr(x) }
}

pub fn lv_color_make(r: u8, g: u8, b: u8) -> lightvgl_sys::lv_color_t {
    unsafe { lightvgl_sys::lv_color_make(r, g, b) }
}

pub fn lv_color_hex(c: u32) -> lightvgl_sys::lv_color_t {
    unsafe { lightvgl_sys::lv_color_hex(c) }
}

pub fn lv_color_hex3(c: u32) -> lightvgl_sys::lv_color_t {
    unsafe { lightvgl_sys::lv_color_hex3(c) }
}

pub fn lv_color_mix(c1: lv_color_t, c2: lv_color_t, mix: u8) -> lightvgl_sys::lv_color_t {
    unsafe { lightvgl_sys::lv_color_mix(c1, c2, mix) }
}

pub fn lv_palette_darken(p: lv_palette_t, lvl: u8) -> lightvgl_sys::lv_color_t {
    unsafe { lightvgl_sys::lv_palette_darken(p, lvl) }
}

#[cfg(LV_USE_LOG)]
pub fn lv_log_add(level: Level, file: &CStr, line: u32, func: &CStr, message: &CStr) {
    crate::logging::lv_log_add(level, file, line, func, message)
}

pub fn lv_obj_add_event_cb<'a, F>(widget: &'a mut Wdg, filter: Event, callback: F)
where
    F: FnMut(lightvgl_sys::lv_event_t) + 'a,
{
    crate::events::lv_obj_add_event_cb(widget, filter, callback)
}

pub fn lv_async_call<F>(callback: F)
where
    F: FnMut() + 'static,
{
    crate::timers::lv_async_call(callback)
}

pub fn lv_screen_active() -> Option<Wdg> {
    unsafe { Wdg::try_from_ptr(lightvgl_sys::lv_screen_active()) }
}

pub fn lv_subject_set_int(subject: &mut Subject, value: i32) {
    unsafe { lightvgl_sys::lv_subject_set_int(subject.raw_mut(), value) }
}

#[rustfmt::skip]
pub fn lv_subject_set_string(subject: &mut Subject, value: &CStr) {
    unsafe { lightvgl_sys::lv_subject_set_pointer(subject.raw_mut(), value.as_ptr().cast::<c_void>().cast_mut()) }
}

pub fn lv_subject_set_color(subject: &mut Subject, value: lv_color_t) {
    unsafe { lightvgl_sys::lv_subject_set_color(subject.raw_mut(), value) }
}

pub fn lv_subject_get_int(subject: &mut Subject) -> i32 {
    unsafe { lightvgl_sys::lv_subject_get_int(subject.raw_mut()) }
}

pub fn lv_subject_get_ptr(subject: &mut Subject) -> *const c_void {
    unsafe { lightvgl_sys::lv_subject_get_pointer(subject.raw_mut()) }
}

pub fn lv_subject_get_color(subject: &mut Subject) -> lv_color_t {
    unsafe { lightvgl_sys::lv_subject_get_color(subject.raw_mut()) }
}

pub fn lv_subject_get_string(subject: &mut Subject) -> &CStr {
    unsafe { CStr::from_ptr(lightvgl_sys::lv_subject_get_string(subject.raw_mut())) }
}

pub fn lv_subject_get_previous_color(subject: &mut Subject) -> lv_color_t {
    unsafe { lightvgl_sys::lv_subject_get_previous_color(subject.raw_mut()) }
}

pub fn lv_subject_get_previous_int(subject: &mut Subject) -> i32 {
    unsafe { lightvgl_sys::lv_subject_get_previous_int(subject.raw_mut()) }
}

pub fn lv_subject_get_previous_string(subject: &mut Subject) -> &CStr {
    unsafe {
        CStr::from_ptr(lightvgl_sys::lv_subject_get_previous_string(
            subject.raw_mut(),
        ))
    }
}
pub fn lv_subject_get_previous_pointer(subject: &mut Subject) -> *const c_void {
    unsafe { lightvgl_sys::lv_subject_get_previous_pointer(subject.raw_mut()) }
}

#[rustfmt::skip]
pub fn lv_subject_add_observer_obj<'a, F>(subject: &'a mut Subject, object: &mut Widget, callback: F)
where
    F: FnMut(*mut lightvgl_sys::lv_observer_t, *mut lightvgl_sys::lv_subject_t) + 'a,
{
    crate::subjects::lv_subject_add_observer_obj(subject, object, callback)
}

// TODO: make lv_event... functions autogenerated
pub fn lv_event_get_target(event: &mut lightvgl_sys::lv_event_t) -> *const c_void {
    unsafe { lightvgl_sys::lv_event_get_target(event) }
}

pub fn lv_event_get_target_obj(event: &mut lightvgl_sys::lv_event_t) -> Option<Wdg> {
    unsafe {
        let target = lightvgl_sys::lv_event_get_target_obj(event);
        Wdg::try_from_ptr(target)
    }
}

pub fn lv_event_get_current_target_obj(event: &mut lightvgl_sys::lv_event_t) -> Option<Wdg> {
    unsafe {
        let target = lightvgl_sys::lv_event_get_current_target_obj(event);
        Wdg::try_from_ptr(target)
    }
}

#[cfg(feature = "no_ecs")]
pub fn lv_obj_add_style(widget: &mut Wdg, mut style: Style, selector: lv_style_selector_t) {
    unsafe { lightvgl_sys::lv_obj_add_style(widget.raw_mut(), style.raw_mut(), selector) }
    core::mem::forget(style);
}

#[cfg(feature = "no_ecs")]
pub fn lv_obj_set_parent(obj: &mut Wdg, parent: &mut Wdg) {
    unsafe { lightvgl_sys::lv_obj_set_parent(obj.raw_mut(), parent.raw_mut()) }
}

include!(concat!(env!("OUT_DIR"), "/generated.rs"));
