use core::ffi::{c_char, c_int, c_short, c_void};

use alloc::vec::Vec;
use yggdrasil_rt::{
    io::RawFd,
    process::{SpawnFlags, SpawnOption, SpawnOptions},
    sys as syscall,
};

use super::{
    sched::__ygg_sched_param_t,
    sys_types::{mode_t, pid_t},
};
use crate::{
    error::{CIntZeroResult, ResultExt},
    headers::errno::Errno,
    util::{NullTerminatedArrayIter, PointerStrExt},
};

#[repr(C)]
pub struct posix_spawnattr_t {}

#[repr(C)]
pub struct posix_spawn_file_actions_t {}

pub const POSIX_SPAWN_RESETIDS: c_int = 1 << 1;
pub const POSIX_SPAWN_SETPGROUP: c_int = 1 << 2;
pub const POSIX_SPAWN_SETSCHEDPARAM: c_int = 1 << 3;
pub const POSIX_SPAWN_SETSCHEDULER: c_int = 1 << 4;
pub const POSIX_SPAWN_SETSIGDEF: c_int = 1 << 5;
pub const POSIX_SPAWN_SETSIGMASK: c_int = 1 << 6;

#[no_mangle]
unsafe extern "C" fn posix_spawn(
    pid: *mut pid_t,
    path: *const c_char,
    _file_actions: *const posix_spawn_file_actions_t,
    _attrp: *const posix_spawnattr_t,
    argv: *const *mut c_char,
    envp: *const *mut c_char,
) -> CIntZeroResult {
    let path = path.ensure_str();
    let argv = NullTerminatedArrayIter::new(argv);
    let envp = NullTerminatedArrayIter::new(envp);
    let args = argv
        .map(|arg| arg.cast_const().ensure_str())
        .collect::<Vec<_>>();
    let envs = envp
        .map(|env| env.cast_const().ensure_str())
        .collect::<Vec<_>>();

    log::info!("posix_spawn({path:?}, {args:?}, {envs:?})");

    let options = SpawnOptions {
        program: path,
        arguments: &args,
        environment: &envs,
        directory: None,
        root: None,
        optional: &[
            SpawnOption::CopyFile {
                source: RawFd::STDIN,
                child: RawFd::STDIN,
            },
            SpawnOption::CopyFile {
                source: RawFd::STDOUT,
                child: RawFd::STDOUT,
            },
            SpawnOption::CopyFile {
                source: RawFd::STDERR,
                child: RawFd::STDERR,
            },
        ],
        flags: SpawnFlags::empty(),
    };
    let id = syscall::spawn_process(&options).e_map_err(Errno::from)?;
    if let Some(pid) = pid.as_mut() {
        *pid = id.bits() as i32;
    }
    log::info!(" -> {id:?}");

    CIntZeroResult::SUCCESS
}

#[no_mangle]
unsafe extern "C" fn posix_spawnp(
    _pid: *mut pid_t,
    _path: *const c_char,
    _file_actions: *const posix_spawn_file_actions_t,
    _attrp: *const posix_spawnattr_t,
    _argv: *const *mut c_char,
    _envp: *const *mut c_char,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawn_file_actions_addclose(
    _file_actions: *mut posix_spawn_file_actions_t,
    _fd: c_int,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawn_file_actions_adddup2(
    _file_actions: *mut posix_spawn_file_actions_t,
    _oldfd: c_int,
    _newfd: c_int,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawn_file_actions_addopen(
    _file_actions: *mut posix_spawn_file_actions_t,
    _fd: c_int,
    _path: *const c_char,
    _oflag: c_int,
    _mode: mode_t,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawn_file_actions_destroy(
    _file_actions: *mut posix_spawn_file_actions_t,
) -> c_int {
    log::warn!("TODO: posix_spawn_file_actions_destroy");
    0
}

#[no_mangle]
unsafe extern "C" fn posix_spawn_file_actions_init(
    _file_actions: *mut posix_spawn_file_actions_t,
) -> c_int {
    log::warn!("TODO: posix_spawn_file_actions_init");
    0
    // todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_destroy(_attrp: *mut posix_spawnattr_t) -> c_int {
    log::warn!("TODO: posix_spawnattr_destroy");
    0
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_getflags(
    _attrp: *const posix_spawnattr_t,
    _flags: *mut c_short,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_getpgroup(
    _attrp: *const posix_spawnattr_t,
    _pgrp: *mut pid_t,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_getschedparam(
    _attrp: *const posix_spawnattr_t,
    _param: *mut __ygg_sched_param_t,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_getschedpolicy(
    _attrp: *const posix_spawnattr_t,
    _policy: *mut c_int,
) -> c_int {
    todo!()
}

// TODO sigset_t
#[no_mangle]
unsafe extern "C" fn posix_spawnattr_getsigdefault(
    _attrp: *const posix_spawnattr_t,
    _sigset: *mut c_void,
) -> c_int {
    todo!()
}
// TODO sigset_t
#[no_mangle]
unsafe extern "C" fn posix_spawnattr_getsigmask(
    _attrp: *const posix_spawnattr_t,
    _sigset: *mut c_void,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_init(_attrp: *mut posix_spawnattr_t) -> c_int {
    log::warn!("TODO: posix_spawnattr_init");
    0
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_setflags(
    _attrp: *mut posix_spawnattr_t,
    _flags: c_short,
) -> c_int {
    log::warn!("TODO: posix_spawnattr_setflags");
    0
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_setpgroup(
    _attrp: *mut posix_spawnattr_t,
    _pgrp: pid_t,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_setschedparam(
    _attrp: *mut posix_spawnattr_t,
    _param: *const __ygg_sched_param_t,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_setschedpolicy(
    _attrp: *mut posix_spawnattr_t,
    _policy: c_int,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_setsigdefault(
    _attrp: *mut posix_spawnattr_t,
    _sigset: *const c_void,
) -> c_int {
    todo!()
}

#[no_mangle]
unsafe extern "C" fn posix_spawnattr_setsigmask(
    _attrp: *mut posix_spawnattr_t,
    _sigset: *const c_void,
) -> c_int {
    log::warn!("TODO: posix_spawnattr_setsigmask");
    0
    // todo!()
}
