#include "filesystem.h"
#include <iostream>
#include <sstream>

namespace fs = std::filesystem;

namespace includecpp {
namespace inbuilds {

// ===== FILE OPERATIONS =====

bool FileSystem::exists(const std::string& path) {
    return fs::exists(path);
}

bool FileSystem::is_file(const std::string& path) {
    return fs::is_regular_file(path);
}

bool FileSystem::is_directory(const std::string& path) {
    return fs::is_directory(path);
}

std::string FileSystem::read_file(const std::string& path) {
    std::ifstream file(path, std::ios::binary);
    if (!file.is_open()) {
        throw std::runtime_error("Cannot open file: " + path);
    }
    std::ostringstream ss;
    ss << file.rdbuf();
    return ss.str();
}

bool FileSystem::write_file(const std::string& path, const std::string& content) {
    std::ofstream file(path, std::ios::binary);
    if (!file.is_open()) {
        return false;
    }
    file << content;
    return file.good();
}

bool FileSystem::append_file(const std::string& path, const std::string& content) {
    std::ofstream file(path, std::ios::binary | std::ios::app);
    if (!file.is_open()) {
        return false;
    }
    file << content;
    return file.good();
}

bool FileSystem::delete_file(const std::string& path) {
    try {
        return fs::remove(path);
    } catch (...) {
        return false;
    }
}

bool FileSystem::copy_file(const std::string& src, const std::string& dst) {
    try {
        fs::copy_file(src, dst, fs::copy_options::overwrite_existing);
        return true;
    } catch (...) {
        return false;
    }
}

bool FileSystem::move_file(const std::string& src, const std::string& dst) {
    try {
        fs::rename(src, dst);
        return true;
    } catch (...) {
        return false;
    }
}

long long FileSystem::file_size(const std::string& path) {
    try {
        return static_cast<long long>(fs::file_size(path));
    } catch (...) {
        return -1;
    }
}

// ===== DIRECTORY OPERATIONS =====

bool FileSystem::create_directory(const std::string& path) {
    try {
        return fs::create_directories(path);
    } catch (...) {
        return false;
    }
}

bool FileSystem::remove_directory(const std::string& path) {
    try {
        return fs::remove_all(path) > 0;
    } catch (...) {
        return false;
    }
}

std::vector<std::string> FileSystem::list_directory(const std::string& path) {
    std::vector<std::string> result;
    try {
        for (const auto& entry : fs::directory_iterator(path)) {
            result.push_back(entry.path().filename().string());
        }
    } catch (...) {
        // Return empty vector on error
    }
    return result;
}

std::vector<std::string> FileSystem::list_files(const std::string& path, const std::string& extension) {
    std::vector<std::string> result;
    try {
        for (const auto& entry : fs::directory_iterator(path)) {
            if (entry.is_regular_file()) {
                if (extension.empty() || entry.path().extension() == extension) {
                    result.push_back(entry.path().filename().string());
                }
            }
        }
    } catch (...) {
        // Return empty vector on error
    }
    return result;
}

std::vector<std::string> FileSystem::list_subdirectories(const std::string& path) {
    std::vector<std::string> result;
    try {
        for (const auto& entry : fs::directory_iterator(path)) {
            if (entry.is_directory()) {
                result.push_back(entry.path().filename().string());
            }
        }
    } catch (...) {
        // Return empty vector on error
    }
    return result;
}

// ===== PATH OPERATIONS =====

std::string FileSystem::get_absolute_path(const std::string& path) {
    try {
        return fs::absolute(path).string();
    } catch (...) {
        return path;
    }
}

std::string FileSystem::get_filename(const std::string& path) {
    return fs::path(path).filename().string();
}

std::string FileSystem::get_extension(const std::string& path) {
    return fs::path(path).extension().string();
}

std::string FileSystem::get_parent_path(const std::string& path) {
    return fs::path(path).parent_path().string();
}

std::string FileSystem::join_paths(const std::string& p1, const std::string& p2) {
    return (fs::path(p1) / p2).string();
}

// ===== FILE INFO =====

std::string FileSystem::get_current_directory() {
    return fs::current_path().string();
}

bool FileSystem::set_current_directory(const std::string& path) {
    try {
        fs::current_path(path);
        return true;
    } catch (...) {
        return false;
    }
}

// ===== FREE FUNCTIONS =====

std::string read_text(const std::string& path) {
    return FileSystem::read_file(path);
}

bool write_text(const std::string& path, const std::string& content) {
    return FileSystem::write_file(path, content);
}

std::vector<std::string> read_lines(const std::string& path) {
    std::vector<std::string> lines;
    std::ifstream file(path);
    if (!file.is_open()) {
        throw std::runtime_error("Cannot open file: " + path);
    }
    std::string line;
    while (std::getline(file, line)) {
        lines.push_back(line);
    }
    return lines;
}

bool write_lines(const std::string& path, const std::vector<std::string>& lines) {
    std::ofstream file(path);
    if (!file.is_open()) {
        return false;
    }
    for (const auto& line : lines) {
        file << line << '\n';
    }
    return file.good();
}

} // namespace inbuilds
} // namespace includecpp
