// Desktop file interface implementation
#include "file_interface.h"
#include <fstream>
#include <algorithm>

namespace mosis {

DesktopFileInterface::DesktopFileInterface(const std::string& assets_path)
    : m_assets_path(assets_path)
{}

std::filesystem::path DesktopFileInterface::ResolveFilePath(const std::string& path) {
    std::string clean_path = path;

    // RmlUi uses URL-style paths where D: becomes D| - convert back
    // Check for pattern like "X|" at start (Windows drive letter)
#ifdef _WIN32
    if (clean_path.length() >= 2 && clean_path[1] == '|' &&
        ((clean_path[0] >= 'A' && clean_path[0] <= 'Z') ||
         (clean_path[0] >= 'a' && clean_path[0] <= 'z'))) {
        clean_path[1] = ':';
    }
#endif

    std::filesystem::path file_path(clean_path);

    // If absolute path, use as-is
    if (file_path.is_absolute()) {
        return file_path;
    }

    // Otherwise resolve relative to assets path
    if (!m_assets_path.empty()) {
        return m_assets_path / file_path;
    }

    return file_path;
}

Rml::FileHandle DesktopFileInterface::Open(const Rml::String& path) {
    auto resolved = ResolveFilePath(path);
    auto* file = new std::ifstream(resolved, std::ios::binary);
    if (!file->is_open()) {
        delete file;
        return 0;
    }
    return reinterpret_cast<Rml::FileHandle>(file);
}

void DesktopFileInterface::Close(Rml::FileHandle file) {
    auto* stream = reinterpret_cast<std::ifstream*>(file);
    if (stream) {
        stream->close();
        delete stream;
    }
}

size_t DesktopFileInterface::Read(void* buffer, size_t size, Rml::FileHandle file) {
    auto* stream = reinterpret_cast<std::ifstream*>(file);
    if (!stream) return 0;
    stream->read(static_cast<char*>(buffer), size);
    return stream->gcount();
}

bool DesktopFileInterface::Seek(Rml::FileHandle file, long offset, int origin) {
    auto* stream = reinterpret_cast<std::ifstream*>(file);
    if (!stream) return false;

    std::ios_base::seekdir dir;
    switch (origin) {
        case SEEK_SET: dir = std::ios::beg; break;
        case SEEK_CUR: dir = std::ios::cur; break;
        case SEEK_END: dir = std::ios::end; break;
        default: return false;
    }

    stream->seekg(offset, dir);
    return !stream->fail();
}

size_t DesktopFileInterface::Tell(Rml::FileHandle file) {
    auto* stream = reinterpret_cast<std::ifstream*>(file);
    if (!stream) return 0;
    return static_cast<size_t>(stream->tellg());
}

size_t DesktopFileInterface::Length(Rml::FileHandle file) {
    auto* stream = reinterpret_cast<std::ifstream*>(file);
    if (!stream) return 0;

    auto current = stream->tellg();
    stream->seekg(0, std::ios::end);
    auto length = stream->tellg();
    stream->seekg(current);

    return static_cast<size_t>(length);
}

bool DesktopFileInterface::LoadFile(const Rml::String& path, Rml::String& out_data) {
    auto resolved = ResolveFilePath(path);
    std::ifstream file(resolved, std::ios::binary | std::ios::ate);
    if (!file.is_open()) {
        return false;
    }

    auto size = file.tellg();
    file.seekg(0, std::ios::beg);

    out_data.resize(static_cast<size_t>(size));
    file.read(out_data.data(), size);

    return true;
}

std::vector<uint8_t> DesktopFileInterface::ReadAll(const std::string& path) {
    auto resolved = ResolveFilePath(path);
    std::ifstream file(resolved, std::ios::binary | std::ios::ate);
    if (!file.is_open()) {
        return {};
    }

    auto size = file.tellg();
    file.seekg(0, std::ios::beg);

    std::vector<uint8_t> data(static_cast<size_t>(size));
    file.read(reinterpret_cast<char*>(data.data()), size);

    return data;
}

bool DesktopFileInterface::FileExists(const std::string& path) {
    auto resolved = ResolveFilePath(path);
    return std::filesystem::exists(resolved);
}

std::vector<std::string> DesktopFileInterface::ListDirectory(const std::string& path) {
    auto resolved = ResolveFilePath(path);
    std::vector<std::string> entries;

    if (!std::filesystem::exists(resolved) || !std::filesystem::is_directory(resolved)) {
        return entries;
    }

    for (const auto& entry : std::filesystem::directory_iterator(resolved)) {
        entries.push_back(entry.path().filename().string());
    }

    std::sort(entries.begin(), entries.end());
    return entries;
}

void DesktopFileInterface::SetAssetsPath(const std::string& path) {
    m_assets_path = path;
}

std::string DesktopFileInterface::GetAssetsPath() const {
    return m_assets_path.string();
}

std::string DesktopFileInterface::ResolvePath(const std::string& relative_path) {
    return ResolveFilePath(relative_path).string();
}

} // namespace mosis
