// Copyright (C) 2019 ~ 2019 UnionTech Software Technology Co.,Ltd.
// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "filecleanupworker.h"
#include "common/vnoteitem.h"

#include <QDir>
#include <QStandardPaths>
#include <QDebug>

FileCleanupWorker::FileCleanupWorker(VNOTE_ALL_NOTES_MAP *qspAllNotesMap, QObject *parent)
    : VNTask(parent)
    , m_qspAllNotesMap(qspAllNotesMap)
{
    qInfo() << "FileCleanupWorker constructor called with notes map:" << (qspAllNotesMap ? "valid" : "null");
}

void FileCleanupWorker::run()
{
    qInfo() << "Starting file cleanup operation";
    if (nullptr == m_qspAllNotesMap) {
        qWarning() << "Notes map is null, cleanup operation aborted";
        return;
    }

    //获取所有语音文件路径
    fillVoiceSet();
    //获取所有图片文件路径
    fillPictureSet();
    //遍历笔记
    if (scanAllNotes()) {
        qInfo() << "Starting cleanup of unused files";
        //清空数据
        cleanVoice();
        cleanPicture();
        qInfo() << "File cleanup operation completed";
    } else {
        qWarning() << "Failed to scan notes, cleanup operation aborted";
    }
}

/**
 * @brief FileCleanupWorker::cleanVoice
 * 清理语音
 */
void FileCleanupWorker::cleanVoice()
{
    qInfo() << "Cleaning voice files, count:" << m_voiceSet.size();
    for (QString path : m_voiceSet) {
        if (!QFile::remove(path)) {
            qWarning() << "Failed to remove voice file:" << path;
        }
    }
    qInfo() << "Voice files cleanup finished";
}

/**
 * @brief FileCleanupWorker::cleanPicture
 * 清理图片
 */
void FileCleanupWorker::cleanPicture()
{
    qInfo() << "Cleaning picture files, count:" << m_pictureSet.size();
    for (QString path : m_pictureSet) {
        if (!QFile::remove(path)) {
            qWarning() << "Failed to remove picture file:" << path;
        }
    }
    qInfo() << "Picture files cleanup finished";
}

/**
 * @brief FileCleanupWorker::fillVoiceSet
 * 获取项目下用户所有的语音完整路径
 */
void FileCleanupWorker::fillVoiceSet()
{
    qDebug() << "Scanning for voice files";
    //文件夹路径
    QString dirPath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/voicenote";
    QDir dir(dirPath);
    if (!dir.exists()) {
        qDebug() << "Voice directory does not exist:" << dirPath;
        return;
    }

    //存放文件路径
    for (auto fileName : dir.entryList(QStringList("*.mp3"), QDir::Files | QDir::NoSymLinks)) {
        m_voiceSet.insert(dirPath + "/" + fileName);
    }
    qDebug() << "Found" << m_voiceSet.size() << "voice files in directory:" << dirPath;
}

/**
 * @brief FileCleanupWorker::fillPictureSet
 * 获取项目下用户所有的图片完整路径
 */
void FileCleanupWorker::fillPictureSet()
{
    qDebug() << "Scanning for picture files";
    //文件夹路径
    QString dirPath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/images";
    QDir dir(dirPath);
    if (!dir.exists()) {
        qDebug() << "Picture directory does not exist:" << dirPath;
        return;
    }

    QStringList filters = {"*.png", "*.jpg", "*.bmp"};
    for (auto fileName : dir.entryList(filters, QDir::Files | QDir::NoSymLinks)) {
        m_pictureSet.insert(dirPath + "/" + fileName);
    }
    qDebug() << "Found" << m_pictureSet.size() << "picture files in directory:" << dirPath;
}

/**
 * @brief FileCleanupWorker::scanAllNotes
 * 遍历所有的笔记
 * @return true: 遍历成功， false: 遍历失败
 */
bool FileCleanupWorker::scanAllNotes()
{
    qDebug() << "Starting scan of all notes";
    //遍历笔记
    QList<VNOTE_ITEMS_MAP *> voiceItems = m_qspAllNotesMap->notes.values();
    for (VNOTE_ITEMS_MAP *voiceItem : voiceItems) {
        QList<VNoteItem *> notes = voiceItem->folderNotes.values();
        for (VNoteItem *note : notes) {
            if (note->htmlCode.isEmpty()) {
                //5.9及以前版本的数据
                scanVoiceByBlocks(note->datas);
            } else {
                //遍历笔记内所有语音
                scanVoiceByHtml(note->htmlCode);
                //遍历笔记内所有图片
                scanPictureByHtml(note->htmlCode);
            }
        }
    }
    qInfo() << "Notes scan finished";
    return true;
}

/**
 * @brief FileCleanupWorker::removeVoicePathBySet
 * 移除语音集合中的指定路径
 * @param path 待移除的路径
 */
void FileCleanupWorker::removeVoicePathBySet(const QString &path)
{
    qInfo() << "Removing voice path from cleanup set:" << path;
    if (path.isEmpty()) {
        qInfo() << "Voice path is empty";
        return;
    }
    //移除笔记内存在的路径
    if (m_voiceSet.remove(path)) {
        qDebug() << "Removed voice path from cleanup set:" << path;
    }
    qInfo() << "Voice path removal finished";
}

/**
 * @brief FileCleanupWorker::removePicturePathBySet
 * 移除图片集合中的指定路径
 * @param path 待移除的路径
 */
void FileCleanupWorker::removePicturePathBySet(const QString &path)
{
    qInfo() << "Removing picture path from cleanup set:" << path;
    if (path.isEmpty()) {
        qInfo() << "Picture path is empty";
        return;
    }
    //移除笔记内存在的路径
    if (m_pictureSet.remove(path)) {
        qDebug() << "Removed picture path from cleanup set:" << path;
    }
    qInfo() << "Picture path removal finished";
}

/**
 * @brief FileCleanupWorker::scanVoiceByHtml
 * 遍历笔记中的语音
 * @param html 笔记html文本
 */
void FileCleanupWorker::scanVoiceByHtml(const QString &htmlCode)
{
    qInfo() << "Scanning voice by HTML";
    //匹配语音块标签的正则表达式
    // QRegExp rx("<div.+jsonkey.+>");
    // rx.setMinimal(true); //最小匹配
    //匹配语音路径的正则表达式
    // QRegExp rxJson("(/\\S+)+/voicenote/[\\w\\-]+\\.mp3");
    // rxJson.setMinimal(false); //最大匹配
    QStringList list;
    int pos = 0;
    //查找语音块
    // while ((pos = rx.indexIn(htmlCode, pos)) != -1) {
    //     //获取语音路径
    //     if (rxJson.indexIn(rx.cap(0)) != -1) {
    //         removeVoicePathBySet(rxJson.cap(0));
    //     }
    //     pos += rx.matchedLength();
    // }
    qInfo() << "Voice HTML scan finished";
}

/**
 * @brief FileCleanupWorker::scanPictureByHtml
 * 遍历笔记中的图片
 * @param html 笔记html文本
 */
void FileCleanupWorker::scanPictureByHtml(const QString &htmlCode)
{
    qInfo() << "Scanning picture by HTML";
    //匹配图片块标签的正则表达式
    // QRegExp rx("<img.+src=.+>");
    // rx.setMinimal(true); //最小匹配
    //匹配本地图片路径的正则表达式（图片位置限制在images文件夹，后缀限制为a-z长度为3到4位）
    // QRegExp rxPath("(/\\S+)+/images/[\\w\\-]+\\.[a-z]{3,4}");
    // rxPath.setMinimal(false); //最大匹配
    int pos = 0;
    //查找图片块
    // while ((pos = rx.indexIn(htmlCode, pos)) != -1) {
    //     //获取图片路径
    //     if (rxPath.indexIn(rx.cap(0)) != -1) {
    //         removePicturePathBySet(rxPath.cap(0));
    //     }
    //     pos += rx.matchedLength();
    // }
    qInfo() << "Picture HTML scan finished";
}

/**
 * @brief scanVoiceByBlocks
 * 遍历5.9及以前版本笔记中的语音路径
 * @param datas
 */
void FileCleanupWorker::scanVoiceByBlocks(const VNOTE_DATAS &datas)
{
    qInfo() << "Scanning voice by blocks, voice block count:" << datas.voiceBlocks.size();
    for (auto data : datas.voiceBlocks) {
        if (VNoteBlock::Voice == data->getType()) {
            removeVoicePathBySet(data->ptrVoice->voicePath);
        }
    }
    qInfo() << "Voice blocks scan finished";
}
