/*
 * Copyright 2015 - 2025 gary@drinkingtea.net
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#pragma once

#if __has_include(<filesystem>) && defined(OX_USE_STDLIB)

#include <filesystem>

#include <ox/std/bit.hpp>
#include "filesystem.hpp"

#define OX_HAS_PASSTHROUGHFS

namespace ox {

constexpr auto HasPassThroughFS = true;

/**
 *
 */
class PassThroughFS: public FileSystem {
	private:
		std::filesystem::path m_path;

	public:
		explicit PassThroughFS(StringViewCR dirPath);

		~PassThroughFS() noexcept override;

		[[nodiscard]]
		String basePath() const noexcept;

		Error mkdir(StringViewCR path, bool recursive) noexcept override;

		Error move(StringViewCR src, StringViewCR dest) noexcept override;

		Result<Vector<String>> ls(StringViewCR dir) const noexcept override;

		template<typename F>
		Error ls(StringViewCR dir, F cb) const noexcept;

		Error resize(uint64_t size, void *buffer) noexcept override;

		Result<FileStat> statInode(uint64_t inode) const noexcept override;

		Result<FileStat> statPath(StringViewCR path) const noexcept override;

		[[nodiscard]]
		uint64_t spaceNeeded(uint64_t size) const noexcept override;

		Result<uint64_t> available() const noexcept override;

		Result<uint64_t> size() const noexcept override;

		[[nodiscard]]
		char *buff() noexcept override;

		Error walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) noexcept override;

		[[nodiscard]]
		bool valid() const noexcept override;

	protected:
		Error readFilePath(StringViewCR path, void *buffer, std::size_t buffSize) noexcept override;

		Error readFileInode(uint64_t inode, void *buffer, std::size_t size) noexcept override;

		Error readFilePathRange(
			StringViewCR path, size_t readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept override;

		Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override;

		Error removePath(StringViewCR path, bool recursive) noexcept override;

		Error writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept override;

		Error writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept override;

	private:
		/**
		 * Strips the leading slashes from a string.
		 */
		[[nodiscard]]
		static std::string_view stripSlash(StringView path) noexcept;

};

template<typename F>
Error PassThroughFS::ls(StringViewCR dir, F cb) const noexcept {
	std::error_code ec;
	const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec);
	OX_RETURN_ERROR(ox::Error(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: ls failed"));
	for (auto &p : di) {
		OX_RETURN_ERROR(cb(p.path().filename().c_str(), 0));
	}
	return {};
}

}

#else

namespace ox {

constexpr auto HasPassThroughFS = false;

}

#endif
