#define STB_IMAGE_IMPLEMENTATION
#include "GLImage.h"
#include <filesystem>
#include <hilog/log.h>
#include <regex>
#include "stb_image.h"

GLImage::GLImage()
    :texture(std::make_shared<GLTexture>()) {}

GLImage::GLImage(const std::string& src, int width, int height)
    :src(src), width(width), height(height), texture(std::make_shared<GLTexture>()) {}

void GLImage::setSrc(const std::string& src, const int width, const int height, std::vector<unsigned char> data) {
    if (this->src == src) return;
    this->src = src;
    this->width = width;
    this->height = height;
    if (!data.empty()) {
        pixels = data;
    }
    reloadImage();
}

void GLImage::setSize(int width, int height) {
    this->width = width;
    this->height = height;
}

void GLImage::setPixels(std::vector<unsigned char> data) {
    if (!data.empty()) {
        pixels = data;
    }
}

std::shared_ptr<GLTexture> GLImage::getTexture() {
    return texture;
}

void GLImage::reloadImage() {
    if (!src.empty()) {
        onLoad(src);
    } else {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "GLImage", "Failed to load '%{public}s'", src.c_str());
    }
}

void GLImage::onLoad(const std::string& src) {
    OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "GLImage", "onLoad: src = %{public}s", src.c_str());
    int width = this->width;
    int height = this->height;
    int channels;
    int reqChannels = 4;           //需要4通道数（RGBA数据）图片才能正常加载显示
    if (!isUrl(src) && isPathByFilesystem(src)) {
        unsigned char *image = stbi_load(src.c_str(), &width, &height, &channels, reqChannels);
        if (image == nullptr) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "GLImage", "onLoad: Failed to load image");
            return;
        }
        //verticalFlip(image, width, height, reqChannels);
        int size = width * height * reqChannels;
        int size1 = sizeof(image);
        pixels = std::vector<unsigned char>(image, image + size);
        stbi_image_free(image);
    }
    
    if (pixels.empty()) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "GLImage", "onLoad: pixels is empty!");
        return;
    }
    
    std::vector<unsigned char> newPixels = pixels;
    verticalFlip(newPixels, width, height, reqChannels);

    unsigned char* data = new unsigned char[newPixels.size()];
    for (size_t i = 0; i < newPixels.size(); ++i) {
        data[i] = newPixels[i];
    }
    
    texture->setPixels(data, width, height);
    
    delete[] data;
}

bool GLImage::isPathByFilesystem(const std::string& str) {
    try {
        std::__fs::filesystem::path p(str);
        return true;
    } catch (const std::__fs::filesystem::filesystem_error&) {
        return false;
    }
}

bool GLImage::isUrl(const std::string& str) {
    try {
        // 正则表达式匹配常见协议（http、https、ftp），忽略大小写
        std::regex pattern(R"(^(https?|ftp)://\S+$)", std::regex::icase);
        return regex_match(str, pattern);
    } catch (const std::regex_error& e) {
        // 处理正则表达式错误（如语法错误）
        OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "GLImage", "judge isUrl failed: '%{public}s'", e.what());
        return false;
    }
}

// 垂直翻转图片数据
void GLImage::verticalFlip(unsigned char* data, int width, int height, int channels) {
    std::vector<unsigned char> temp(width * channels);
    for (int y = 0; y < height / 2; ++y) {
        int topIndex = y * width * channels;
        int bottomIndex = (height - 1 - y) * width * channels;

        // 交换当前行和对应的底部行
        for (int x = 0; x < width * channels; ++x) {
            temp[x] = data[topIndex + x];
            data[topIndex + x] = data[bottomIndex + x];
            data[bottomIndex + x] = temp[x];
        }
    }
}

void GLImage::verticalFlip(std::vector<unsigned char>& data, int width, int height, int channels) {
    if (data.size() >= width * height * channels) {
        for (int y = 0; y < height / 2; ++y) {
            for (int x = 0; x < width; ++x) {
                int index1 = (y * width + x) * channels;
                int index2 = ((height - 1 - y) * width + x) * channels;
                for (int c = 0; c < channels; ++c) {
                    std::swap(data[index1 + c], data[index2 + c]);
                }
            }
        }
    }
}