// file: poc006/src/main.rs

mod qt_gst;

use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QString, QUrl};
use glib::translate::ToGlibPtr;
use gstreamer as gst;
use gst::prelude::*;
use std::env;
use std::path::PathBuf;

fn main() {
    if let Err(err) = gst::init() {
        eprintln!("gst init failed: {err}");
        return;
    }

    let pipeline = gst::Pipeline::new();

    let src = match gst::ElementFactory::make("v4l2src").build() {
        Ok(v) => v,
        Err(err) => {
            eprintln!("failed to create v4l2src: {err}");
            return;
        }
    };

    let videoconvert = match gst::ElementFactory::make("videoconvert").build() {
        Ok(v) => v,
        Err(err) => {
            eprintln!("failed to create videoconvert: {err}");
            return;
        }
    };

    let glupload = match gst::ElementFactory::make("glupload").build() {
        Ok(v) => v,
        Err(err) => {
            eprintln!("failed to create glupload: {err}");
            return;
        }
    };

    let glcolorconvert = match gst::ElementFactory::make("glcolorconvert").build() {
        Ok(v) => v,
        Err(err) => {
            eprintln!("failed to create glcolorconvert: {err}");
            return;
        }
    };

    // Important : créer qml6glsink avant le chargement du QML
    let sink = match gst::ElementFactory::make("qml6glsink").build() {
        Ok(v) => v,
        Err(err) => {
            eprintln!("failed to create qml6glsink: {err}");
            return;
        }
    };

    if let Err(err) = pipeline.add_many([&src, &videoconvert, &glupload, &glcolorconvert, &sink]) {
        eprintln!("failed to add elements to pipeline: {err}");
        return;
    }

    if let Err(err) =
        gst::Element::link_many([&src, &videoconvert, &glupload, &glcolorconvert, &sink])
    {
        eprintln!("failed to link pipeline: {err}");
        let _ = pipeline.set_state(gst::State::Null);
        return;
    }

    let mut app = QGuiApplication::new();
    let mut engine = QQmlApplicationEngine::new();

    let current_dir = match env::current_dir() {
        Ok(v) => v,
        Err(err) => {
            eprintln!("failed to get current_dir: {err}");
            let _ = pipeline.set_state(gst::State::Null);
            return;
        }
    };

    let qml_path: PathBuf = current_dir.join("qml/main.qml");
    let qml_path = match qml_path.canonicalize() {
        Ok(v) => v,
        Err(err) => {
            eprintln!("failed to resolve qml/main.qml: {err}");
            let _ = pipeline.set_state(gst::State::Null);
            return;
        }
    };

    let qml_path_str = match qml_path.to_str() {
        Some(v) => v.to_string(),
        None => {
            eprintln!("qml path is not valid UTF-8: {}", qml_path.display());
            let _ = pipeline.set_state(gst::State::Null);
            return;
        }
    };

    println!("loading qml from: {}", qml_path_str);

    if let Some(mut engine_ref) = engine.as_mut() {
        let qml_url = QUrl::from_local_file(&QString::from(qml_path_str));
        engine_ref.as_mut().load(&qml_url);

        let video_item = qt_gst::ffi::find_video_item(engine_ref.as_mut());
        if video_item.is_null() {
            eprintln!("failed to find QML videoItem");
            let _ = pipeline.set_state(gst::State::Null);
            return;
        }

        let sink_ptr =
            <gst::Element as ToGlibPtr<'_, *mut gst::ffi::GstElement>>::to_glib_none(&sink).0
                as usize;

        let ok = unsafe { qt_gst::ffi::bind_sink_widget(sink_ptr, video_item) };
        if !ok {
            eprintln!("failed to bind qml6glsink widget");
            let _ = pipeline.set_state(gst::State::Null);
            return;
        }

        let pipeline_ptr =
            <gst::Pipeline as ToGlibPtr<'_, *mut gst::ffi::GstPipeline>>::to_glib_none(&pipeline).0
                as usize;

        if !qt_gst::ffi::schedule_pipeline_play(engine_ref.as_mut(), pipeline_ptr) {
            eprintln!("failed to schedule pipeline play");
            let _ = pipeline.set_state(gst::State::Null);
            return;
        }
    } else {
        eprintln!("failed to create QQmlApplicationEngine");
        let _ = pipeline.set_state(gst::State::Null);
        return;
    }

    if let Some(app_ref) = app.as_mut() {
        app_ref.exec();
    }

    let _ = pipeline.set_state(gst::State::Null);
}
