#include "FileHelper.h"

#include <QDir>
#include <QSet>
#include <QApplication>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QFile>

const QString kConfigName = "/config/TouchScreen.json";
const QString kResouce = "/config";

constexpr qint16 kDefualtPort = 9527;

template<typename T>
T clamp(const T& value, const T& minValue, const T& maxValue)
{
	return qMax(minValue, qMin(value, maxValue));
}

QStringList FileHelper::GetAllMediaFiles(const QString& path, bool* success) {
    QDir dir(path);
    if (!dir.exists()) {
        if (success) { *success = false; }
        return QStringList();
    }

    QStringList nameFilters;
    nameFilters << "*.png" << "*.jpg" << "*.jpeg" << "*.gif" << "*.bmp"
        << "*.mp4" << "*.avi" << "*.mkv" << "*.mov" << "*.wmv";

    QStringList files = dir.entryList(nameFilters, QDir::Files);
    if (success) { *success = true; }
    return files;
}

bool FileHelper::GeneratJsonConfig() {
    QString resourcePath = GetResoucePath();
    bool success = false;
    QStringList mediaFiles = GetAllMediaFiles(resourcePath, &success);
    if (!success) {
        qDebug() << "GetAllMediaFiles failes";
        return false;
    }

    QJsonArray jsonArray;
    qint32 index = 0;
    for (const auto& path : mediaFiles) {
        QJsonObject jsonObject;
        jsonObject["index"] = index++;
        jsonObject["path"] = path;
        jsonArray.append(jsonObject);

    }

    QJsonObject jsonObject;
    jsonObject["data"] = jsonArray;
    jsonObject["port"] = kDefualtPort;

    // 创建 JSON 文档
    
    const QString configPath = QApplication::applicationDirPath() + kConfigName;
    QFile outputFile(configPath);
    if (outputFile.open(QIODevice::WriteOnly)) {
        QJsonDocument jsonDocument(jsonObject);
        outputFile.write(jsonDocument.toJson());
        outputFile.close();
        qDebug() << "JSON file saved at:" << configPath;
        return true;
    }
    else {
        qDebug() << "Failed to open file for writing. path=" << configPath;
    }
    return false;
}

bool FileHelper::GetItemFromJsonConfig(Config* config) {
    if (nullptr == config) {
        qDebug() << "config is nullptr";
        return false;
    }
    const QString configPath = QApplication::applicationDirPath() + kConfigName;
    QFile inputFile(configPath);
    if (!inputFile.open(QIODevice::ReadOnly))
    {
        qDebug() << "Failed to open file for reading. config=" << configPath;
        return false;
    }

    // 读取文件内容并关闭文件
    QByteArray fileData = inputFile.readAll();
    inputFile.close();

    // 解析 JSON 数据
    QJsonParseError jsonError;
    QJsonDocument jsonDocument = QJsonDocument::fromJson(fileData, &jsonError);
    if (jsonError.error != QJsonParseError::NoError)
    {
        qDebug() << "Failed to parse JSON data:" << jsonError.errorString() << "  config=" << configPath;
        return false;
    }

    // 将 JSON 数据转换为 JSON 对象
    QJsonObject jsonObject = jsonDocument.object();
    if (jsonObject.contains("ip") && jsonObject["ip"].isString()) {
        config->ip = jsonObject["ip"].toString();
    } else {
        config->ip = "127.0.0.1";
    }
    if (jsonObject.contains("port") && jsonObject["port"].isDouble()) {
        config->port = jsonObject["port"].toInt();
    }
    else {
        config->port = kDefualtPort;
    }

    if (!jsonObject.contains("data") || !jsonObject["data"].isArray()) {
        qDebug() << "Failed to parse JSON not find key of data, or data value is not array config=" << configPath;
        return false;
    }

    const QJsonArray datas = jsonObject["data"].toArray();
    for (int i = 0; i < datas.size(); ++i) {
       const QJsonObject data = datas.at(i).toObject();
       MedianItem mediaItem;
       if (!data.contains("name") || !data["name"].isString()) {
           qDebug() << "Failed to parse JSON not find key of name, or name value is not array config=" << configPath;
           return false;
       }

        mediaItem.name = data["name"].toString();
       
	   if (!data.contains("index") || !data["index"].isDouble()) {
		   qDebug() << "Failed to parse JSON not find key of index, or index value is not array config=" << configPath;
		   return false;
	   }
	   mediaItem.index = data["index"].toInt();

	   if (!data.contains("type") || !data["type"].isDouble()) {
		   qDebug() << "Failed to parse JSON not find key of type, or type value is not array config=" << configPath;
		   return false;
	   }
	   mediaItem.type = data["type"].toInt();

	   if (!data.contains("data") || !data["data"].isArray()) {
		   qDebug() << "Failed to parse JSON not find key of data, or data value is not array config=" << configPath;
		   return false;
	   }
	   const QJsonArray itemDatas = data["data"].toArray();
       QSet<int32_t> test;
       for (int i = 0; i < itemDatas.size(); ++i) {
		   const QJsonObject mediaInfoData = itemDatas.at(i).toObject();
           MediaInfo mediaInfo;
		   if (!mediaInfoData.contains("id") || !mediaInfoData["id"].isDouble()) {
			   qDebug() << "Failed to parse JSON not find key of id, or name id is not array config=" << configPath;
			   return false;
		   }
		   mediaInfo.id = mediaInfoData["id"].toInt();

		   if (!mediaInfoData.contains("button") || !mediaInfoData["button"].isString()) {
			   qDebug() << "Failed to parse JSON not find key of button, or button value is not array config=" << configPath;
			   return false;
		   }
           mediaInfo.button = mediaInfoData["button"].toString();

		   if (!mediaInfoData.contains("name") || !mediaInfoData["name"].isString()) {
			  // qDebug() << "Failed to parse JSON not find key of name, or name value is not array config=" << configPath;
               mediaInfo.name = "";
			   //return false;
           } else {
               mediaInfo.name = mediaInfoData["name"].toString();
           }
           

		   if (!mediaInfoData.contains("describe") || !mediaInfoData["describe"].isString()) {
			   qDebug() << "Failed to parse JSON not find key of describe, or describe value is not string config=" << configPath;
			   return false;
		   }
           mediaInfo.describe = mediaInfoData["describe"].toString();

		   if (!mediaInfoData.contains("images") || !mediaInfoData["images"].isArray()) {
			   qDebug() << "Failed to parse JSON not find key of images, or images value is not array config=" << configPath;
			   return false;
		   }
           const QJsonArray images = mediaInfoData["images"].toArray();
           for (int i = 0; i < images.size(); ++i) {
               mediaInfo.images.append(images[i].toString());
           }

		   if (!mediaInfoData.contains("start") || !mediaInfoData["start"].isDouble()) {
               mediaInfo.start = 0;
           }
           else {
               int start = mediaInfoData["start"].toInt();
               mediaInfo.start = clamp(start, 0, 2);
           }
           
		   if (!mediaInfoData.contains("end") || !mediaInfoData["end"].isString()) {
               mediaInfo.end = QPointF(0.0f, 0.0f);
           }
           else {
               QString end = mediaInfoData["end"].toString();
			   QStringList pointCoordinates = end.split(",");

			   if (pointCoordinates.size() == 2) {
				   bool xConversionOk, yConversionOk;
				   qreal x = pointCoordinates[0].trimmed().toDouble(&xConversionOk);
				   qreal y = pointCoordinates[1].trimmed().toDouble(&yConversionOk);

				   if (xConversionOk && yConversionOk) {
                       mediaInfo.end = QPointF(x, y);
				   }
			   }
           }

           if (!mediaInfoData.contains("scope") || !mediaInfoData["scope"].isArray()) {
               qDebug() << "Failed to parse JSON not find key of scope, or scope value is not array config=" << configPath;
               return false;
           }
           else {
               const QJsonArray scope = mediaInfoData["scope"].toArray();
               if (scope.size() == 5) {
                   mediaInfo.scope.x = scope[0].toInt();
                   mediaInfo.scope.y = scope[1].toInt();
                   mediaInfo.scope.width = scope[2].toInt();
                   mediaInfo.scope.height = scope[3].toInt();
                   mediaInfo.scope.shape = scope[4].toInt();
               } else {
                   qDebug() << "Failed to parse JSON not find key of scope, or scope value is not 5 config=" << configPath;
                   return false;
               }
           }
           if (!mediaInfoData.contains("landmark") || !mediaInfoData["landmark"].isArray()) {
               qDebug() << "Failed to parse JSON not find key of scope, or scope value is not array config=" << configPath;
               mediaInfo.landmark = QPoint(0, 0);
           }
           else {
               const QJsonArray landmark = mediaInfoData["landmark"].toArray();
               if (landmark.size() == 2) {
                   mediaInfo.landmark = QPoint(landmark[0].toInt(), landmark[1].toInt());
               }
               else {
                   qDebug() << "Failed to parse JSON not find key of landmark, or scope value is not 2 config=" << configPath;
                   return false;
               }
           }

           if (test.contains(mediaInfo.id)) {
               qDebug() << "test.contains is exits" << mediaInfo.id;
               return false;
           }
           test.insert(mediaInfo.id);

   /*        if (mediaInfo.id != i + 1) {
               qDebug() << "test.contains is exits" << mediaInfo.id;
               return false;
           }*/
           if (mediaItem.datas.contains(mediaInfo.button)) {
               qDebug() << "dmediaItem.datas is exits" << mediaInfo.button;
               return false;
           }
           mediaItem.datas.insert(mediaInfo.button, std::move(mediaInfo));
       }
    
       if (config->datas.contains(mediaItem.index)) {
           qDebug() << "datas.contains is exits" << mediaItem.index;
           return false;
       }

       config->datas.insert(mediaItem.index, std::move(mediaItem));
    }
    return true;
}

bool FileHelper::SaveItemToJsonConfig(Config* config) {
    QJsonObject jsonObject;
   // jsonObject.insert("ip", config->ip);
    jsonObject.insert("port", config->port);

    QJsonArray datas;
    for (const auto& data : config->datas) {
        QJsonObject dataObject;
        dataObject.insert("name", data.name);
        dataObject.insert("index", data.index);
        dataObject.insert("type", data.type);

        QJsonArray dataItems;
        for (const auto& item : data.datas) {
            QJsonObject itemObject;
            itemObject.insert("id", item.id);
            itemObject.insert("button", item.button);
            itemObject.insert("name", item.name);
            itemObject.insert("start", item.start);
            itemObject.insert("end", QString("%1,%2").arg(item.end.x()).arg(item.end.y()));

            QJsonArray scope;
            scope.append(item.scope.x);
            scope.append(item.scope.y);
            scope.append(item.scope.width);
            scope.append(item.scope.height);
            scope.append(item.scope.shape);
            itemObject.insert("scope", scope);

            QJsonArray landmark;
            landmark.append(item.landmark.x());
            landmark.append(item.landmark.y());
            itemObject.insert("landmark", landmark);

            itemObject.insert("describe", item.describe);

            QJsonArray images;
            for (auto& image : item.images) {
                images.append(image);
            }
            itemObject.insert("images", images);

            dataItems.append(itemObject);
        }
        dataObject.insert("data", dataItems);
        datas.append(dataObject);
    }

    jsonObject.insert("data", datas);
    const QString configPath = QApplication::applicationDirPath() + kConfigName;
    QFile inputFile(configPath);
    if (!inputFile.open(QIODevice::WriteOnly))
    {
        qDebug() << "Failed to open file for reading. config=" << configPath;
        return false;
    }

    QJsonDocument doc(jsonObject);
    inputFile.write(doc.toJson());
    inputFile.close();
  
    return true;
}

QString FileHelper::GetResoucePath() {
    const QString configPath = QApplication::applicationDirPath() + kResouce;
    return configPath;
}