#pragma once

#include "IObserver.h"
#include "TypeConverterHelper.h"
#include "tsk/auto/tsk_auto.h"
#include "InvertedIndex.h"
#include "UnManagedFileInfo.h"
#include <string>
#include <memory>
#include <vcclr.h> // 包含 gcroot
#include <functional>
#include <vector>

namespace TSKWrapper
{
    /// <summary>
    /// 全盘索引构建
    /// </summary>
    public class FullDiskIndexBuilder : public TskAuto
    {
    private:
        gcroot<IObserver^> m_observer;
        gcroot<IFilterStrategy^> m_filterStrategy;
        std::unique_ptr<InvertedIndex> m_index;

    public:
        /// <summary>
        /// 是否外部停止扫描
        /// </summary>
        bool IsScanStopped = false;

    public:
        /// <summary>
        /// 非托管构造函数
        /// </summary>
        FullDiskIndexBuilder() : m_observer(nullptr), m_filterStrategy(nullptr), m_index(nullptr)
        {
        }

        ~FullDiskIndexBuilder() override
        {
            m_index = nullptr;
        }

        /// <summary>
        /// 工厂方法，用于创建和初始化 FullDiskIndexBuilder 实例
        /// </summary>
        static FullDiskIndexBuilder* Create(IObserver^ observer, IFilterStrategy^ filterStrategy, const std::string& dbPath)
        {
            FullDiskIndexBuilder* builder = new FullDiskIndexBuilder();
            builder->Initialize(observer, filterStrategy, dbPath);
            return builder;
        }

        /// <summary>
        /// 初始化方法
        /// </summary>
        void Initialize(IObserver^ observer, IFilterStrategy^ filterStrategy, std::string dbPath)
        {
            if (observer == nullptr || filterStrategy == nullptr)
            {
                throw std::invalid_argument("Observer and FilterStrategy cannot be null.");
            }

            m_observer = observer;
            m_filterStrategy = filterStrategy;
            m_index = std::make_unique<InvertedIndex>(dbPath);
        }

    protected:
        TSK_RETVAL_ENUM processFile(TSK_FS_FILE* fs_file, const char* path) override
        {
            if (IsScanStopped)
            {
                return TSK_STOP;
            }

            if (fs_file == nullptr)
            {
                return TSK_OK;
            }

            FileInfo^ fileInfo = TypeConverterHelper::ConvertToFileInfo(fs_file, path);
            std::string filePath = TypeConverterHelper::ConvertManagedStringToStdString(fileInfo->Path);
            std::string fileName = TypeConverterHelper::ConvertManagedStringToStdString(fileInfo->Name);
            TSK_FS_META_TYPE_ENUM fileType = static_cast<TSK_FS_META_TYPE_ENUM>(fileInfo->Type);
            int64_t fileSize = fileInfo->Size;
            std::string modificationDate = TypeConverterHelper::ConvertManagedStringToStdString(fileInfo->ModificationDate);
            TSK_FS_META_FLAG_ENUM fileFlag = static_cast<TSK_FS_META_FLAG_ENUM>(fileInfo->Flag);
            std::string originalName = TypeConverterHelper::ConvertManagedStringToStdString(fileInfo->OriginalFileName);
            std::string originalPath = TypeConverterHelper::ConvertManagedStringToStdString(fileInfo->OriginalFilePath);

            UnManagedFileInfo fileInfoObj(fileName, filePath, fileType, fileSize, modificationDate, fileFlag,
                fileInfo->IsRecycleBinFile, originalPath, originalName);

            m_index->addWord(fileName, fileInfoObj);

            bool filterConditionsAreMet = m_filterStrategy->ShouldInclude(fileInfo);
            m_observer->OnFileFound(fileInfo, filterConditionsAreMet);
            return TSK_OK;
        }

        uint8_t handleError() override
        {
            const std::vector<TskAuto::error_record> errorList = getErrorList();
            String^ managedError = TypeConverterHelper::ConvertErrorListToString(errorList);
            if (managedError != nullptr)
            {
                m_observer->OnError(managedError);
            }
            return TSK_OK;
        }

    public:
        void search(const std::string& word, const std::function<void(std::vector<UnManagedFileInfo>)>& onBatchResult) const
        {
            if (m_index)
            {
                m_index->search(word, onBatchResult);
            }
        }

        void saveDatabase() const
        {
            if (m_index)
            {
                m_index->saveDatabase();
            }
        }

        void loadDatabase() const
        {
            if (m_index)
            {
                m_index->loadDatabase();
                m_index->search("", [this](const std::vector<UnManagedFileInfo>& results) {
                    for (const auto& result : results)
                    {
                        FileInfo^ managedFileInfo = gcnew FileInfo();
                        managedFileInfo->Name = TypeConverterHelper::ConvertStdStringToManagedString(result.Name);
                        managedFileInfo->Path = TypeConverterHelper::ConvertStdStringToManagedString(result.Path);
                        managedFileInfo->Type = static_cast<EnumFsMetaType>(result.Type);
                        managedFileInfo->Size = result.Size;
                        managedFileInfo->ModificationDate = TypeConverterHelper::ConvertStdStringToManagedString(result.ModificationDate);
                        managedFileInfo->Flag = static_cast<EnumFileMetaFlag>(result.Flag);
                        managedFileInfo->IsRecycleBinFile = result.IsRecycleBinFile;
                        managedFileInfo->OriginalFilePath = TypeConverterHelper::ConvertStdStringToManagedString(result.OriginalFilePath);
                        managedFileInfo->OriginalFileName = TypeConverterHelper::ConvertStdStringToManagedString(result.OriginalFileName);

                        bool filterConditionsAreMet = m_filterStrategy->ShouldInclude(managedFileInfo);
                        m_observer->OnFileFound(managedFileInfo, filterConditionsAreMet);
                    }
                    });
            }
        }
    };
}
#include "FileInfo.h"
#include "FullDiskIndexManager.h"
#include <filesystem>
using namespace msclr::interop;
using namespace System::Collections::Generic;
namespace fs = std::filesystem;
namespace TSKWrapper
{
    FullDiskIndexManager::FullDiskIndexManager() :
        m_fullDiskIndexBuilder(nullptr),
        m_statsLock(gcnew Object())
    {
    }
    FullDiskIndexManager::~FullDiskIndexManager()
    {
        if (scanThread != nullptr && scanThread->IsAlive)
        {
            StopScan();
            scanThread->Abort();
            scanThread->Join();
        }

        if (m_fullDiskIndexBuilder != nullptr)
        {
            delete m_fullDiskIndexBuilder;
            m_fullDiskIndexBuilder = nullptr;
        }
    }
    void FullDiskIndexManager::StartIndex(IFilterStrategy^ filterStrategy, bool rebuildIndex)
    {
        if (m_fullDiskIndexBuilder != nullptr)
        {
            delete m_fullDiskIndexBuilder;
            m_fullDiskIndexBuilder = nullptr;
        }

        std::string dbFilePath = "FileRecoveryIndex.db";
        m_fullDiskIndexBuilder = FullDiskIndexBuilder::Create(this, filterStrategy, dbFilePath);

        if (rebuildIndex)
        {
            if (fs::exists(dbFilePath))
            {
                fs::remove(dbFilePath);
            }

            scanThread = gcnew Thread(gcnew ThreadStart(this, &FullDiskIndexManager::ScanDrive));
            scanThread->IsBackground = true;
            scanThread->Start();
        }
        else
        {
            if (fs::exists(dbFilePath))
            {
                m_fullDiskIndexBuilder->loadDatabase();
                IndexCompleted();
            }
            else
            {
                scanThread = gcnew Thread(gcnew ThreadStart(this, &FullDiskIndexManager::ScanDrive));
                scanThread->IsBackground = true;
                scanThread->Start();
            }
        }
    }

    void FullDiskIndexManager::SearchFiles(String^ query)
    {
        if (m_fullDiskIndexBuilder != nullptr)
        {
            std::string stdQuery = TypeConverterHelper::ConvertManagedStringToStdString(query);
            m_fullDiskIndexBuilder->search(stdQuery, [this](const std::vector<UnManagedFileInfo>& batchResult) {
                List<FileInfo^>^ managedResults = gcnew List<FileInfo^>();
                for (const auto& result : batchResult)
                {
                    FileInfo^ managedFileInfo = gcnew FileInfo();
                    managedFileInfo->Name = TypeConverterHelper::ConvertStdStringToManagedString(result.Name);
                    managedFileInfo->Path = TypeConverterHelper::ConvertStdStringToManagedString(result.Path);
                    managedFileInfo->Type = static_cast<EnumFsMetaType>(result.Type);
                    managedFileInfo->Size = result.Size;
                    managedFileInfo->ModificationDate = TypeConverterHelper::ConvertStdStringToManagedString(result.ModificationDate);
                    managedFileInfo->Flag = static_cast<EnumFileMetaFlag>(result.Flag);
                    managedResults->Add(managedFileInfo);
                }
                BatchResult(managedResults);
                });
        }
    }

    void FullDiskIndexManager::StopScan()
    {
        if (m_fullDiskIndexBuilder != nullptr)
        {
            m_fullDiskIndexBuilder->IsScanStopped = true;
        }
    }

    void FullDiskIndexManager::ScanDrive()
    {
        array<String^>^ driveLetters = TypeConverterHelper::GetAllDriveLetters();
        std::vector<const TSK_TCHAR*> images = TypeConverterHelper::PrepareImages(driveLetters);
        for (const auto& image : images)
        {
            const TSK_TCHAR* singleImageArray[1] = { image };
            uint8_t rv = m_fullDiskIndexBuilder->openImage(1, singleImageArray, TSK_IMG_TYPE_DETECT, 0);
            if (rv != 0)
            {
                String^ imagePath = TypeConverterHelper::ToManagedString(image);
                OnError("打开图像失败: " + imagePath);
                continue;
            }
            rv = m_fullDiskIndexBuilder->findFilesInImg();
            if (rv != 0)
            {
                String^ imagePath = TypeConverterHelper::ToManagedString(image);
                OnError("在图像中查找文件失败: " + imagePath);
            }
            m_fullDiskIndexBuilder->closeImage();
        }

        m_fullDiskIndexBuilder->saveDatabase();
        IndexCompleted();
    }

    void FullDiskIndexManager::OnFileFound(FileInfo^ fileInfo, bool filterConditionsAreMet)
    {
        if (filterConditionsAreMet)
        {
            FileFound(fileInfo);
        }
    }
    void FullDiskIndexManager::OnError(String^ errorMessage)
    {
        ErrorOccurred(errorMessage);
    }
}
请优化以上代码，FullDiskIndexBuilder是非托管类，FullDiskIndexManager是托管类，我希望SearchFiles能正常通过BatchResult回调结果给客户端