/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--

Namaste

Copyright (C) 2019, 2021-2023  Anonymous

There are several releases over multiple years,
they are listed as ranges, such as: "2021-2023".

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/

#![cfg(unix)]

use {
    std::{
        env,
        fs::{self, File},
        io::{Error, ErrorKind, Write},
        os::unix::{
            net::{UnixListener, UnixStream},
            prelude::AsRawFd,
        },
        thread,
    },
    namaste::{Result, UdsxUnixStream},
};

const ID_OF_STREAMS: &[u8] = &[
    0x69, 0x2e, 0xac, 0xa4, 0x74, 0x2a, 0x79, 0xd2, 0x01, 0xc5, 0x9f, 0xae, 0xff, 0x96, 0x87, 0x83, 0xee, 0xab, 0x06, 0xe5, 0x80, 0xd0, 0xe4,
    0x54, 0xc0, 0x70, 0x1c, 0xc3, 0x44, 0x08, 0xe6, 0xcd, 0xbd, 0x4e, 0x81, 0x2c, 0xff, 0xb6, 0xbe, 0x97, 0x24, 0x48, 0x66, 0x2d, 0xf2, 0x3d,
    0xc9, 0xad, 0xa1, 0x9a, 0x78, 0x75, 0x86, 0xe7, 0xe9, 0xbf, 0x7b, 0xef, 0x43, 0xf4, 0xe4, 0xb5, 0x16, 0x75,
];

const ID_OF_IOE: &[u8] = &[
    0x03, 0xd5, 0x07, 0x5d, 0xd1, 0xd1, 0xe3, 0x49, 0x7f, 0xc9, 0xe1, 0xb7, 0xeb, 0xac, 0xd6, 0x33, 0xe0, 0xf8, 0x7a, 0x09, 0xa0, 0xdd, 0x20,
    0x72, 0x6f, 0x16, 0x2c, 0x7a, 0x27, 0x7f, 0x6c, 0x47, 0x4f, 0x7f, 0xb2, 0x23, 0x50, 0x30, 0x8f, 0x0e, 0x13, 0x07, 0x3c, 0x13, 0xd2, 0x96,
    0xdf, 0x58, 0x3a, 0x68, 0xe4, 0xc0, 0x47, 0x15, 0x01, 0xa7, 0x0f, 0xc3, 0x3e, 0xd1, 0x8c, 0x87, 0xd0, 0x20,
];

#[test]
fn udsx_unix_stream() -> Result<()> {
    const LOOP_OF_STREAMS: usize = 9_999;

    assert_ne!(ID_OF_IOE, ID_OF_STREAMS);

    let sock_file = env::temp_dir().join(format!("{}::9a334508-d5f77782-98d4ef2c-1f786f98.sock", namaste::CODE_NAME));
    if sock_file.exists() {
        fs::remove_file(&sock_file)?;
    }

    let file = File::open(file!())?;
    let file_size = file.metadata()?.len();

    let server = UnixListener::bind(&sock_file)?;
    let thread = thread::spawn(move || -> Result<_> {
        let client = server.accept()?.0;
        unsafe {
            for _ in 0..LOOP_OF_STREAMS {
                client.recv_ioe(ID_OF_IOE)?;

                let [file] = client.recv_streams::<_, File, 1>(ID_OF_STREAMS)?;
                assert_eq!(file.metadata()?.len(), file_size);
            }
        }
        Ok(())
    });

    let mut stream = UnixStream::connect(&sock_file)?;
    for _ in 0..LOOP_OF_STREAMS {
        stream.send_ioe(ID_OF_IOE)?;
        stream.send_streams(ID_OF_STREAMS, [file.as_raw_fd()])?;
    }
    stream.flush()?;

    match thread.join() {
        Ok(result) => match result {
            Ok(()) => Ok(()),
            Err(err) => {
                eprintln!("{:?}", err);
                Err(err)
            },
        },
        Err(err) => {
            eprintln!("{:?}", err);
            Err(Error::new(ErrorKind::Other, format!("{:?}", err)))
        },
    }
}
