#include "rendering/shader_backend.hpp"

#include <algorithm>
#include <fstream>
#include <sstream>

namespace Rendering {

    namespace {

        auto trimString(const std::string& str) -> std::string {
            const std::size_t start = str.find_first_not_of(" \t\r\n");
            const std::size_t end = str.find_last_not_of(" \t\r\n");
            if (start != std::string::npos && end != std::string::npos) {
                return str.substr(start, end - start + 1);
            }
            return "";
        }

    }  // namespace

    auto loadFileToString(const std::filesystem::path& path, std::string& out) -> bool {
        std::ifstream ifs(path, std::ios::in | std::ios::binary);
        if (!ifs) { return false; }
        std::ostringstream ss;
        ss << ifs.rdbuf();
        out = ss.str();
        return true;
    }

    auto parseMetaFile(const std::filesystem::path& meta_path) -> ShaderMetadata {
        ShaderMetadata metadata;
        std::ifstream ifs(meta_path);
        if (!ifs) { return metadata; }

        std::string line;
        while (std::getline(ifs, line)) {
            const std::size_t colon = line.find(':');
            if (colon == std::string::npos) { continue; }

            std::string key = line.substr(0, colon);
            std::string value = trimString(line.substr(colon + 1));

            std::transform(key.begin(), key.end(), key.begin(),
                [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
            key = trimString(key);

            if (key == "name") { metadata.name = value; }
            else if (key == "author") { metadata.author = value; }
            else if (key == "ichannel0") { metadata.iChannel0 = value; }
            else if (key == "ichannel1") { metadata.iChannel1 = value; }
            else if (key == "ichannel2") { metadata.iChannel2 = value; }
            else if (key == "ichannel3") { metadata.iChannel3 = value; }
        }
        return metadata;
    }

    auto extractShaderMetadata(const std::string& source) -> ShaderMetadata {
        ShaderMetadata metadata;

        std::istringstream stream(source);
        std::string line;
        int line_count = 0;
        constexpr int MAX_LINES_TO_CHECK = 30;

        while (std::getline(stream, line) && line_count < MAX_LINES_TO_CHECK) {
            line_count++;

            const std::size_t pos = line.find("//");
            if (pos == std::string::npos) { continue; }

            const std::string comment = line.substr(pos + 2);
            std::string lower = comment;
            std::transform(lower.begin(), lower.end(), lower.begin(),
                [](unsigned char c) { return static_cast<char>(std::tolower(c)); });

            auto valueAfterColon = [&]() {
                return trimString(comment.substr(comment.find(':') + 1));
            };

            if (lower.find("name:") != std::string::npos) {
                metadata.name = valueAfterColon();
            } else if (lower.find("author:") != std::string::npos) {
                metadata.author = valueAfterColon();
            } else if (lower.find("ichannel0:") != std::string::npos) {
                metadata.iChannel0 = valueAfterColon();
            } else if (lower.find("ichannel1:") != std::string::npos) {
                metadata.iChannel1 = valueAfterColon();
            } else if (lower.find("ichannel2:") != std::string::npos) {
                metadata.iChannel2 = valueAfterColon();
            } else if (lower.find("ichannel3:") != std::string::npos) {
                metadata.iChannel3 = valueAfterColon();
            }
        }

        return metadata;
    }

}  // namespace Rendering
