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

#include "searcher.h"
#include "analyzers/chineseanalyzer.h"
#include "utils/string_helper.h"
#include <glib.h>
#include <iostream>

using namespace Lucene;

namespace anything {

Searcher::Searcher() {
}

Searcher::~Searcher() {
    // 清理 Lucene 资源
    if (reader) {
        reader->close();
    }
}

bool Searcher::initialize(const std::string& index_path) {
    if (!checkIndexPath(index_path)) {
        std::cerr << "Invalid index path: " << index_path << std::endl;
        return false;
    }

    try {
        // 打开索引目录
        FSDirectoryPtr dir = FSDirectory::open(StringUtils::toUnicode(index_path.c_str()));
        reader = IndexReader::open(dir, true);
        searcher = newLucene<IndexSearcher>(reader);
        return true;
    } catch (const LuceneException& e) {
        std::cerr << "Failed to initialize searcher: " << StringUtils::toUTF8(e.getError()) << std::endl;
        return false;
    }
}

std::vector<std::string> Searcher::search(const std::string& path,
                                          const std::string& query,
                                          int max_results,
                                          bool wildcard_query) {
    std::vector<std::string> results;
    
    if (!searcher) {
        std::cerr << "Searcher not initialized" << std::endl;
        return results;
    }

    try {
        BooleanQueryPtr finalQuery = newLucene<BooleanQuery>();
        String query_string = StringUtils::toLower(StringUtils::toUnicode(query.c_str()));

        // 文件名搜索
        if (wildcard_query) {
            TermPtr term = newLucene<Term>(L"file_name_lower", query_string);
            QueryPtr wildcardQuery = newLucene<WildcardQuery>(term);
            finalQuery->add(wildcardQuery, BooleanClause::MUST);
        } else {
            // 创建查询解析器
            AnalyzerPtr analyzer = newLucene<ChineseAnalyzer>();
            QueryParserPtr parser = newLucene<QueryParser>(LuceneVersion::LUCENE_CURRENT, L"file_name", analyzer);

            // 解析查询
            QueryPtr parserQuery = parser->parse(query_string);
            finalQuery->add(parserQuery, BooleanClause::MUST);
        }

        // 搜索路径前缀过滤
        {
            g_autofree gchar *canonical = g_canonicalize_filename (path.c_str(), NULL);
            TermPtr term = newLucene<Term>(L"ancestor_paths", StringUtils::toUnicode(canonical));
            QueryPtr prefixQuery = newLucene<TermQuery>(term);
            finalQuery->add(prefixQuery, BooleanClause::MUST);
        }

        // 执行搜索
        if (max_results == 0) {
            max_results = reader->numDocs();
        }
        std::cout << "Doc num: " << reader->numDocs() << std::endl;
        TopDocsPtr topDocs = searcher->search(finalQuery, max_results);
        results.reserve(topDocs->totalHits);
        
        // 处理搜索结果
        for (int32_t i = 0; i < topDocs->totalHits; ++i) {
            ScoreDocPtr scoreDoc = topDocs->scoreDocs[i];
            DocumentPtr doc = searcher->doc(scoreDoc->doc);
            std::stringstream ss;
            ss << StringUtils::toUTF8(doc->get(L"full_path"))
                << "<\\>" << StringUtils::toUTF8(doc->get(L"file_type"))
                << "<\\>" << StringUtils::toUTF8(doc->get(L"file_ext"))
                << "<\\>" << StringUtils::toUTF8(doc->get(L"birth_time"))
                << "<\\>" << StringUtils::toUTF8(doc->get(L"modify_time"))
                << "<\\>" << StringUtils::toUTF8(doc->get(L"file_size_str"))
                << "<\\>" << StringUtils::toUTF8(doc->get(L"pinyin"))
                << "<\\>" << StringUtils::toUTF8(doc->get(L"pinyin_acronym"))
                << "<\\>" << StringUtils::toUTF8(doc->get(L"is_hidden"));
            std::string result = ss.str();
            results.push_back(result);
        }
    } catch (const LuceneException& e) {
        std::cerr << "Search failed: " << StringUtils::toUTF8(e.getError()) << std::endl;
    }

    return results;
}

bool Searcher::checkIndexPath(const std::string& path) {
    return g_file_test(path.c_str(), G_FILE_TEST_IS_DIR);
}

} // namespace anything