#![allow(
    clippy::as_conversions,
    clippy::missing_safety_doc,
    clippy::missing_panics_doc,
    clippy::undocumented_unsafe_blocks,
    missing_docs
)]
pub mod api;
pub mod utils;
#[allow(
    clippy::as_conversions,
    clippy::default_trait_access,
    clippy::let_underscore_untyped,
    clippy::missing_docs_in_private_items,
    clippy::multiple_unsafe_ops_per_block,
    clippy::ptr_as_ptr,
    clippy::undocumented_unsafe_blocks,
    clippy::empty_structs_with_brackets,
    clippy::use_self,
    clippy::wildcard_imports,
    let_underscore_drop,
    unused_qualifications
)]
mod api_bridge_generated;
use std::{
    ffi::{c_void, CString},
    marker::PhantomData,
    panic, ptr,
};
use dart_sys::{Dart_Handle, _Dart_Handle};
use derive_more::Display;
use libc::c_char;
use crate::{
    api::dart::utils::new_panic_error,
    media::{FacingMode, MediaDeviceKind, MediaKind, MediaSourceKind},
    platform::utils::{
        c_str_into_string, dart_api, free_dart_native_string,
        handle::DartHandle, string_into_c_str,
    },
};
pub use crate::media::MediaDirection;
pub use self::{
    api::{
        ConnectionHandle, Jason, LocalMediaTrack, MediaManagerHandle,
        ReconnectHandle, RemoteMediaTrack, RoomCloseReason, RoomHandle,
    },
    utils::DartError as Error,
};
pub fn propagate_panic<T>(f: impl FnOnce() -> T) -> T {
    panic::catch_unwind(panic::AssertUnwindSafe(f)).unwrap_or_else(|_| {
        let exception = unsafe { new_panic_error() };
        unsafe {
            dart_api::propagate_error(exception);
        }
        unreachable!("`Dart_PropagateError` should do early return")
    })
}
pub trait ForeignClass: Sized {
    #[must_use]
    fn into_ptr(self) -> ptr::NonNull<Self> {
        ptr::NonNull::from(Box::leak(Box::new(self)))
    }
    #[must_use]
    unsafe fn from_ptr(this: ptr::NonNull<Self>) -> Self {
        *Box::from_raw(this.as_ptr())
    }
}
pub trait PrimitiveEnum: TryFrom<i64> {}
#[derive(Clone, Copy, Debug)]
#[repr(u8)]
pub enum MemoryOwner {
    Rust = 0,
    Dart = 1,
}
#[allow(missing_copy_implementations)] #[derive(Debug)]
#[repr(u8)]
pub enum DartValue {
    None,
    Ptr(ptr::NonNull<c_void>),
    Handle(ptr::NonNull<Dart_Handle>),
    String(ptr::NonNull<c_char>, MemoryOwner),
    Int(i64),
    Float(f64),
    Bool(bool),
}
impl Drop for DartValue {
    fn drop(&mut self) {
        match self {
            Self::Float(_)
            | Self::Bool(_)
            | Self::Int(_)
            | Self::Ptr(_)
            | Self::Handle(_)
            | Self::None => {}
            Self::String(ptr, MemoryOwner::Dart) => unsafe {
                free_dart_native_string(*ptr);
            },
            Self::String(ptr, MemoryOwner::Rust) => unsafe {
                drop(CString::from_raw(ptr.as_ptr()));
            },
        }
    }
}
impl From<()> for DartValue {
    fn from(_: ()) -> Self {
        Self::None
    }
}
impl<T: ForeignClass> From<T> for DartValue {
    fn from(val: T) -> Self {
        Self::Ptr(val.into_ptr().cast())
    }
}
impl<T: ForeignClass> From<Option<T>> for DartValue {
    fn from(val: Option<T>) -> Self {
        val.map_or(Self::None, |t| Self::from(t))
    }
}
impl From<String> for DartValue {
    fn from(string: String) -> Self {
        Self::String(string_into_c_str(string), MemoryOwner::Rust)
    }
}
impl From<Option<String>> for DartValue {
    fn from(val: Option<String>) -> Self {
        val.map_or(Self::None, Self::from)
    }
}
impl From<Option<i64>> for DartValue {
    fn from(val: Option<i64>) -> Self {
        val.map_or(Self::None, Self::from)
    }
}
impl From<ptr::NonNull<Dart_Handle>> for DartValue {
    fn from(handle: ptr::NonNull<*mut _Dart_Handle>) -> Self {
        Self::Handle(handle)
    }
}
impl From<Option<ptr::NonNull<Dart_Handle>>> for DartValue {
    fn from(val: Option<ptr::NonNull<Dart_Handle>>) -> Self {
        val.map_or(Self::None, Self::from)
    }
}
impl From<Dart_Handle> for DartValue {
    fn from(handle: Dart_Handle) -> Self {
        Self::Handle(ptr::NonNull::from(Box::leak(Box::new(handle))))
    }
}
impl From<Option<Dart_Handle>> for DartValue {
    fn from(val: Option<Dart_Handle>) -> Self {
        val.map_or(Self::None, Self::from)
    }
}
impl From<Error> for DartValue {
    fn from(err: Error) -> Self {
        Self::Handle(err.into())
    }
}
impl From<Option<Error>> for DartValue {
    fn from(val: Option<Error>) -> Self {
        val.map_or(Self::None, Self::from)
    }
}
impl From<MediaDirection> for DartValue {
    fn from(val: MediaDirection) -> Self {
        Self::from(val as u8)
    }
}
impl From<bool> for DartValue {
    fn from(val: bool) -> Self {
        Self::Bool(val)
    }
}
impl From<f32> for DartValue {
    fn from(val: f32) -> Self {
        Self::Float(f64::from(val))
    }
}
impl From<f64> for DartValue {
    fn from(val: f64) -> Self {
        Self::Float(val)
    }
}
macro_rules! impl_from_num_for_dart_value {
    ($arg:ty) => {
        impl From<$arg> for DartValue {
            fn from(val: $arg) -> Self {
                DartValue::Int(i64::from(val))
            }
        }
    };
}
impl_from_num_for_dart_value!(i8);
impl_from_num_for_dart_value!(i16);
impl_from_num_for_dart_value!(i32);
impl_from_num_for_dart_value!(i64);
impl_from_num_for_dart_value!(u8);
impl_from_num_for_dart_value!(u16);
impl_from_num_for_dart_value!(u32);
#[derive(Debug)]
#[repr(transparent)]
pub struct DartValueArg<T>(DartValue, PhantomData<*const T>);
impl<F, T> From<F> for DartValueArg<T>
where
    DartValue: From<F>,
{
    fn from(from: F) -> Self {
        Self(DartValue::from(from), PhantomData)
    }
}
impl<T> TryFrom<DartValueArg<T>> for ptr::NonNull<c_void> {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::Ptr(ptr) => Ok(ptr),
            DartValue::None
            | DartValue::Handle(_)
            | DartValue::String(_, _)
            | DartValue::Int(_)
            | DartValue::Bool(_)
            | DartValue::Float(_) => Err(DartValueCastError {
                expectation: "NonNull<c_void>",
                value: value.0,
            }),
        }
    }
}
impl<T> TryFrom<DartValueArg<T>> for Option<ptr::NonNull<c_void>> {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::None => Ok(None),
            DartValue::Ptr(ptr) => Ok(Some(ptr)),
            DartValue::Handle(_)
            | DartValue::String(_, _)
            | DartValue::Float(_)
            | DartValue::Bool(_)
            | DartValue::Int(_) => Err(DartValueCastError {
                expectation: "Option<NonNull<c_void>>",
                value: value.0,
            }),
        }
    }
}
impl TryFrom<DartValueArg<Self>> for String {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::String(c_str, _) => unsafe {
                Ok(c_str_into_string(c_str))
            },
            DartValue::None
            | DartValue::Ptr(_)
            | DartValue::Handle(_)
            | DartValue::Float(_)
            | DartValue::Bool(_)
            | DartValue::Int(_) => Err(DartValueCastError {
                expectation: "String",
                value: value.0,
            }),
        }
    }
}
impl TryFrom<DartValueArg<()>> for () {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<()>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::None => Ok(()),
            DartValue::Ptr(_)
            | DartValue::Handle(_)
            | DartValue::String(_, _)
            | DartValue::Float(_)
            | DartValue::Bool(_)
            | DartValue::Int(_) => Err(DartValueCastError {
                expectation: "()",
                value: value.0,
            }),
        }
    }
}
impl TryFrom<DartValueArg<Self>> for Option<DartHandle> {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::None => Ok(None),
            DartValue::Handle(handle) => {
                let handle = unsafe { *handle.as_ptr() };
                Ok(Some(unsafe { DartHandle::new(handle) }))
            }
            DartValue::Ptr(_)
            | DartValue::Bool(_)
            | DartValue::Float(_)
            | DartValue::String(_, _)
            | DartValue::Int(_) => Err(DartValueCastError {
                expectation: "Option<DartHandle>",
                value: value.0,
            }),
        }
    }
}
impl TryFrom<DartValueArg<Self>> for Option<String> {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::None => Ok(None),
            DartValue::String(c_str, _) => unsafe {
                Ok(Some(c_str_into_string(c_str)))
            },
            DartValue::Ptr(_)
            | DartValue::Bool(_)
            | DartValue::Float(_)
            | DartValue::Handle(_)
            | DartValue::Int(_) => Err(DartValueCastError {
                expectation: "Option<String>",
                value: value.0,
            }),
        }
    }
}
impl<T> TryFrom<DartValueArg<T>> for Dart_Handle {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::Handle(c_ptr) => Ok(unsafe { unbox_dart_handle(c_ptr) }),
            DartValue::None
            | DartValue::Ptr(_)
            | DartValue::String(_, _)
            | DartValue::Float(_)
            | DartValue::Bool(_)
            | DartValue::Int(_) => Err(DartValueCastError {
                expectation: "Dart_Handle",
                value: value.0,
            }),
        }
    }
}
impl TryFrom<DartValueArg<Self>> for DartHandle {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::Handle(handle) => {
                let handle = unsafe { unbox_dart_handle(handle) };
                Ok(unsafe { Self::new(handle) })
            }
            DartValue::None
            | DartValue::Ptr(_)
            | DartValue::String(_, _)
            | DartValue::Float(_)
            | DartValue::Bool(_)
            | DartValue::Int(_) => Err(DartValueCastError {
                expectation: "DartHandle",
                value: value.0,
            }),
        }
    }
}
impl<T> TryFrom<DartValueArg<T>> for ptr::NonNull<Dart_Handle> {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::Handle(c_str) => Ok(c_str),
            DartValue::None
            | DartValue::Ptr(_)
            | DartValue::String(_, _)
            | DartValue::Float(_)
            | DartValue::Bool(_)
            | DartValue::Int(_) => Err(DartValueCastError {
                expectation: "NonNull<Dart_Handle>",
                value: value.0,
            }),
        }
    }
}
impl<T> TryFrom<DartValueArg<T>> for Option<ptr::NonNull<Dart_Handle>> {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::None => Ok(None),
            DartValue::Handle(c_str) => Ok(Some(c_str)),
            DartValue::Ptr(_)
            | DartValue::Bool(_)
            | DartValue::Float(_)
            | DartValue::String(_, _)
            | DartValue::Int(_) => Err(DartValueCastError {
                expectation: "Option<NonNull<Dart_Handle>>",
                value: value.0,
            }),
        }
    }
}
macro_rules! impl_primitive_dart_value_try_from {
    ($arg:ty) => {
        impl TryFrom<DartValueArg<Self>> for $arg {
            type Error = DartValueCastError;
            fn try_from(
                value: DartValueArg<Self>,
            ) -> Result<Self, Self::Error> {
                match value.0 {
                    DartValue::Int(num) => {
                        Ok(Self::try_from(num).map_err(
                            |_| DartValueCastError {
                                expectation: stringify!($arg),
                                value: value.0,
                            }
                        )?)
                    }
                    _ => Err(DartValueCastError {
                        expectation: stringify!($arg),
                        value: value.0,
                    }),
                }
            }
        }
        impl TryFrom<DartValueArg<Self>> for Option<$arg> {
            type Error = DartValueCastError;
            fn try_from(
                value: DartValueArg<Self>
            ) -> Result<Self, Self::Error> {
                match value.0 {
                    DartValue::None => Ok(None),
                    DartValue::Int(num) => {
                        Ok(Some(<$arg>::try_from(num).map_err(
                            |_| DartValueCastError {
                                expectation: concat!(
                                    "Option<",
                                    stringify!($arg),
                                    ">"
                                ),
                                value: value.0,
                            }
                        )?))
                    }
                    _ => Err(DartValueCastError {
                        expectation: concat!("Option<", stringify!($arg), ">"),
                        value: value.0,
                    }),
                }
            }
        }
    };
    ($($arg:ty),+) => {
        $(impl_primitive_dart_value_try_from!($arg);)+
    }
}
impl_primitive_dart_value_try_from![i8, i16, i32, i64, u8, u16, u32];
impl<T: PrimitiveEnum> TryFrom<DartValueArg<T>> for i64 {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<T>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::Int(num) => Ok(num),
            DartValue::None
            | DartValue::Ptr(_)
            | DartValue::Handle(_)
            | DartValue::Float(_)
            | DartValue::Bool(_)
            | DartValue::String(_, _) => Err(DartValueCastError {
                expectation: "i64",
                value: value.0,
            }),
        }
    }
}
impl<T: PrimitiveEnum> TryFrom<DartValueArg<Self>> for Option<T> {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::None => Ok(None),
            DartValue::Int(num) => match T::try_from(num) {
                Ok(variant) => Ok(Some(variant)),
                Err(_) => Err(DartValueCastError {
                    expectation: "Option<i64>",
                    value: value.0,
                }),
            },
            DartValue::Ptr(_)
            | DartValue::Float(_)
            | DartValue::Bool(_)
            | DartValue::Handle(_)
            | DartValue::String(_, _) => Err(DartValueCastError {
                expectation: "Option<i64>",
                value: value.0,
            }),
        }
    }
}
impl TryFrom<DartValueArg<Self>> for Option<f64> {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::None => Ok(None),
            DartValue::Float(num) => Ok(Some(num)),
            DartValue::Ptr(_)
            | DartValue::Handle(_)
            | DartValue::String(..)
            | DartValue::Int(_)
            | DartValue::Bool(_) => Err(DartValueCastError {
                expectation: "Option<f64>",
                value: value.0,
            }),
        }
    }
}
impl TryFrom<DartValueArg<Self>> for Option<bool> {
    type Error = DartValueCastError;
    fn try_from(value: DartValueArg<Self>) -> Result<Self, Self::Error> {
        match value.0 {
            DartValue::None => Ok(None),
            DartValue::Bool(num) => Ok(Some(num)),
            DartValue::Ptr(_)
            | DartValue::Handle(_)
            | DartValue::String(..)
            | DartValue::Int(_)
            | DartValue::Float(_) => Err(DartValueCastError {
                expectation: "Option<bool>",
                value: value.0,
            }),
        }
    }
}
#[derive(Debug, Display)]
#[display(fmt = "expected `{}`, but got: `{:?}`", expectation, value)]
pub struct DartValueCastError {
    expectation: &'static str,
    value: DartValue,
}
impl PrimitiveEnum for MediaSourceKind {}
impl PrimitiveEnum for FacingMode {}
impl PrimitiveEnum for MediaDirection {}
impl TryFrom<i64> for MediaSourceKind {
    type Error = i64;
    fn try_from(value: i64) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(Self::Device),
            1 => Ok(Self::Display),
            _ => Err(value),
        }
    }
}
impl TryFrom<i64> for FacingMode {
    type Error = i64;
    fn try_from(value: i64) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(Self::User),
            1 => Ok(Self::Environment),
            2 => Ok(Self::Left),
            3 => Ok(Self::Right),
            _ => Err(value),
        }
    }
}
impl TryFrom<i64> for MediaKind {
    type Error = i64;
    fn try_from(value: i64) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(Self::Audio),
            1 => Ok(Self::Video),
            _ => Err(value),
        }
    }
}
impl TryFrom<i64> for MediaDeviceKind {
    type Error = i64;
    fn try_from(value: i64) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(Self::AudioInput),
            1 => Ok(Self::VideoInput),
            2 => Ok(Self::AudioOutput),
            _ => Err(value),
        }
    }
}
impl TryFrom<i64> for MediaDirection {
    type Error = i64;
    fn try_from(value: i64) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(Self::SendRecv),
            1 => Ok(Self::SendOnly),
            2 => Ok(Self::RecvOnly),
            3 => Ok(Self::Inactive),
            _ => Err(value),
        }
    }
}
#[allow(clippy::missing_const_for_fn)]
#[no_mangle]
pub unsafe extern "C" fn unbox_dart_handle(
    val: ptr::NonNull<Dart_Handle>,
) -> Dart_Handle {
    *val.as_ptr()
}
#[no_mangle]
pub unsafe extern "C" fn free_boxed_dart_handle(
    val: ptr::NonNull<Dart_Handle>,
) {
    let handle = Box::from_raw(val.as_ptr());
    dart_api::delete_persistent_handle(*handle);
}
#[no_mangle]
pub unsafe extern "C" fn box_dart_handle(
    val: Dart_Handle,
) -> ptr::NonNull<Dart_Handle> {
    let persisted = dart_api::new_persistent_handle(val);
    ptr::NonNull::from(Box::leak(Box::new(persisted)))
}
#[no_mangle]
pub unsafe extern "C" fn box_foreign_value(
    val: DartValue,
) -> ptr::NonNull<DartValue> {
    ptr::NonNull::from(Box::leak(Box::new(val)))
}
#[cfg(feature = "mockable")]
#[allow(clippy::missing_docs_in_private_items)]
mod dart_value_extern_tests_helpers {
    use super::*;
    use crate::platform::set_panic_hook;
    #[no_mangle]
    pub unsafe extern "C" fn fire_panic() {
        set_panic_hook();
        propagate_panic(|| panic!("Panicking"));
    }
}