/*
 * Copyright (c), Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
 */
//! ### Logging Unimplemented
//! Many error handling in the current module should be logged,
//! and since the log module has not yet been completed,
//! it will return false or mark it as unimplemented

#![feature(io_error_more)]

use std::{fs, fs::Metadata, io::ErrorKind};

#[cfg(windows)]
use windows::{
    Win32::{
        Foundation::{CloseHandle, HANDLE, HLOCAL, LocalFree},
    },
};

use self::FileErrorKind::*;

pub enum FileErrorKind<'a> {
    ErrorNone,
    InvalidFileName(&'a str),
    NoSuchFile(&'a str),
    DirNotSupported(&'a str),
    UnknownError(String, &'a str),
    UnsupportedFIleType(&'a str),
    BadPermission(&'a str),
    InconsistentOwner(&'a str),
    BadFile(&'a str),
}

pub struct FileExt;

impl FileExt {
    pub fn validate(path: &str) -> FileErrorKind {
        let mut metadata = fs::metadata(path);

        match metadata {
            Ok(ref mut meta) => {
                if meta.is_dir() {
                    return DirNotSupported(path);
                }

                if meta.is_symlink() {
                    let path = fs::read_link(path).unwrap();
                    *meta = fs::metadata(path).unwrap();
                }

                #[cfg(unix)]
                {
                    use std::os::unix::fs::MetadataExt;

                    let mode = meta.mode();
                    if mode & 0o400 == 0 || mode & 0o022 != 0 {
                        return BadPermission(path);
                    }
                }

                #[cfg(unix)]
                if !check_owner(meta) {
                    return InconsistentOwner(path);
                }
            }
            Err(e) =>
                return match e.kind() {
                    ErrorKind::InvalidFilename => InvalidFileName(path),
                    ErrorKind::NotFound => NoSuchFile(path),
                    _ => UnknownError(e.to_string(), path),
                },
        }

        ErrorNone
    }
}

#[cfg(unix)]
fn check_owner(meta: &Metadata) -> bool {
    use std::os::unix::fs::MetadataExt;

    let uid = meta.uid();
    let euid = unsafe { libc::geteuid() };

    uid == euid
}

#[cfg(windows)]
fn local_free_rs<T>(ptr: *mut T) {
    if !ptr.is_null() {
        unsafe {
            LocalFree(Some(HLOCAL(ptr.cast())));
        }
    }
}

#[cfg(windows)]
fn close_handle_rs(handle: HANDLE) {
    unsafe {
        if CloseHandle(handle).is_err() {
            unimplemented!()
        }
    }
}