/**
 * @file FileSystem.h
 * @author apio (cloudapio.eu)
 * @brief APIs to read and modify the general file system.
 *
 * @copyright Copyright (c) 2023, the Luna authors.
 *
 */

#pragma once
#include <luna/Result.h>
#include <luna/StringView.h>
#include <os/Path.h>
#include <sys/stat.h>
#include <sys/types.h>

namespace os
{
    namespace FileSystem
    {
        /**
         * @brief Check whether a given path exists.
         *
         * @param path The path to check.
         * @param follow_symlinks If path is a symbolic link, whether to follow it (defaults to true).
         * @return true The path exists.
         * @return false The path does not exist, or it was a symbolic link and following it leaded to a nonexistent
         * path.
         */
        bool exists(const Path& path, bool follow_symlinks = true);

        /**
         * @brief Check whether a given path is a directory.
         *
         * @param path The path to check.
         * @param follow_symlinks If path is a symbolic link, whether to follow it (defaults to false).
         * @return true The path is a directory, or the path was a symbolic link and following it leaded to a directory.
         * @return false The path does not exist, or it is not a directory.
         */
        bool is_directory(const Path& path, bool follow_symlinks = false);

        /**
         * @brief Retrieve file status information.
         *
         * @param path The path to examine.
         * @param st The buffer to store file status information in.
         * @param follow_symlinks If path is a symbolic link, whether to follow it and retrieve its target's status, or
         * otherwise retrieve the symbolic link's status (defaults to true).
         * @return Result<void> Whether the operation succeeded.
         */
        Result<void> stat(const Path& path, struct stat& st, bool follow_symlinks = true);

        /**
         * @brief Create a new directory in the file system.
         *
         * @param path The path for the new directory.
         * @param mode The file permissions to apply to the new directory.
         * @return Result<void> Whether the operation succeeded.
         */
        Result<void> create_directory(StringView path, mode_t mode);

        /**
         * @brief Remove a file or empty directory from the file system. (The file will continue to exist if there are
         * other hard links to it or a process still has it open.)
         *
         * @param path The path to remove.
         * @return Result<void> Whether the operation succeeded.
         */
        Result<void> remove(const Path& path);

        /**
         * @brief Remove a directory tree from the file system recursively, deleting subfiles and subdirectories as
         * well.
         *
         * @param path The path to remove.
         * @return Result<void> Whether the operation succeeded.
         */
        Result<void> remove_tree(const Path& path);

        /**
         * @brief Read the target of a symbolic link.
         *
         * @param path The symbolic link's path.
         * @return Result<String> If the path was not a symbolic link, an empty string, otherwise the symbolic link's
         * target.
         */
        Result<String> readlink(const Path& path);

        /**
         * @brief Read the current process's working directory.
         *
         * @return Result<String> The working directory as an owned String object.
         */
        Result<String> working_directory();

        /**
         * @brief Fetch the current user' home directory.
         *
         * @return Result<String> The home directory as an owned String object.
         */
        Result<String> home_directory();

        /**
         * @brief Change the current process's working directory.
         *
         * @param path The new working directory.
         * @return Result<void> Whether the operation succeeded.
         */
        Result<void> change_directory(StringView path);
    }
}