// SPDX-License-Identifier: MPL-2.0

use ostd::mm::VmIo;

use super::SyscallReturn;
use crate::{
    fs::{
        file_table::{FdFlags, FileDesc},
        pipe,
        utils::CreationFlags,
    },
    prelude::*,
};

pub fn sys_pipe2(fds: Vaddr, flags: u32, ctx: &Context) -> Result<SyscallReturn> {
    debug!("flags: {:?}", flags);

    let (pipe_reader, pipe_writer) = pipe::new_file_pair()?;

    let fd_flags = if CreationFlags::from_bits_truncate(flags).contains(CreationFlags::O_CLOEXEC) {
        FdFlags::CLOEXEC
    } else {
        FdFlags::empty()
    };

    let file_table = ctx.thread_local.borrow_file_table();
    let mut file_table_locked = file_table.unwrap().write();

    let pipe_fds = PipeFds {
        reader_fd: file_table_locked.insert(pipe_reader, fd_flags),
        writer_fd: file_table_locked.insert(pipe_writer, fd_flags),
    };
    debug!("pipe_fds: {:?}", pipe_fds);

    if let Err(err) = ctx.user_space().write_val(fds, &pipe_fds) {
        file_table_locked.close_file(pipe_fds.reader_fd).unwrap();
        file_table_locked.close_file(pipe_fds.writer_fd).unwrap();
        return Err(err.into());
    }

    Ok(SyscallReturn::Return(0))
}

pub fn sys_pipe(fds: Vaddr, ctx: &Context) -> Result<SyscallReturn> {
    self::sys_pipe2(fds, 0, ctx)
}

#[derive(Debug, Clone, Copy, Pod)]
#[repr(C)]
struct PipeFds {
    reader_fd: FileDesc,
    writer_fd: FileDesc,
}
