/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "paimon/global_index/lucene/jieba_analyzer.h"

#include "cppjieba/Jieba.hpp"
#include "gtest/gtest.h"
#include "lucene++/LuceneHeaders.h"
#include "paimon/global_index/lucene/lucene_utils.h"
#include "paimon/memory/memory_pool.h"
#include "paimon/testing/utils/testharness.h"
namespace paimon::lucene::test {
class JiebaAnalyzerTest : public ::testing::Test, public ::testing::WithParamInterface<int32_t> {
 public:
    void SetUp() override {}
    void TearDown() override {}
    Lucene::TokenStreamPtr CreateJiebaTokenizer(bool with_position) const {
        return CreateJiebaTokenizer(with_position, L"我爱机器学习");
    }

    Lucene::TokenStreamPtr CreateJiebaTokenizer(bool with_position,
                                                const Lucene::String& text) const {
        auto pool = GetDefaultPool();
        std::string dictionary_dir = LuceneUtils::GetJiebaDictionaryDir().value();
        auto jieba = std::make_shared<cppjieba::Jieba>(
            dictionary_dir + "/jieba.dict.utf8", dictionary_dir + "/hmm_model.utf8",
            dictionary_dir + "/user.dict.utf8", dictionary_dir + "/idf.utf8",
            dictionary_dir + "/stop_words.utf8");
        auto reader = Lucene::newLucene<Lucene::StringReader>(text);
        int32_t buffer_size = GetParam();
        JiebaTokenizerContext context(/*tokenize_mode=*/"query", with_position, jieba, pool,
                                      buffer_size);
        auto analyzer = Lucene::newLucene<JiebaAnalyzer>(context);
        return analyzer->tokenStream(/*field_name*/ L"f0", reader);
    }
};

TEST_P(JiebaAnalyzerTest, TestSimple) {
    auto tokenizer = CreateJiebaTokenizer(/*with_position=*/false);

    auto term_att = tokenizer->addAttribute<Lucene::TermAttribute>();

    tokenizer->reset();
    std::vector<Lucene::String> results;
    while (tokenizer->incrementToken()) {
        results.push_back(term_att->term());
    }
    tokenizer->end();
    tokenizer->close();
    std::vector<Lucene::String> expected = {L"爱", L"机器", L"学习"};
    ASSERT_EQ(expected, results);
}

TEST_P(JiebaAnalyzerTest, TestWithPosition) {
    auto tokenizer = CreateJiebaTokenizer(/*with_position=*/true);

    auto term_att = tokenizer->addAttribute<Lucene::TermAttribute>();
    auto pos_att = tokenizer->addAttribute<Lucene::PositionIncrementAttribute>();

    tokenizer->reset();
    std::vector<Lucene::String> results;
    std::vector<int32_t> result_pos;
    int32_t pos = 0;
    while (tokenizer->incrementToken()) {
        pos += pos_att->getPositionIncrement();
        result_pos.push_back(pos);
        results.push_back(term_att->term());
    }
    tokenizer->end();
    tokenizer->close();

    std::vector<Lucene::String> expected = {L"爱", L"机器", L"学习"};
    std::vector<int32_t> expected_pos = {1, 2, 3};
    ASSERT_EQ(expected, results);
    ASSERT_EQ(expected_pos, result_pos);
}

TEST_P(JiebaAnalyzerTest, TestNormalize) {
    auto tokenizer = CreateJiebaTokenizer(
        /*with_position=*/false,
        L"由于购买了Iphone14，我越来越热爱网上学习了！Happy work, happy day! \n\t");

    auto term_att = tokenizer->addAttribute<Lucene::TermAttribute>();

    tokenizer->reset();
    std::vector<Lucene::String> results;
    while (tokenizer->incrementToken()) {
        results.push_back(term_att->term());
    }
    tokenizer->end();
    tokenizer->close();
    std::vector<Lucene::String> expected = {L"购买", L"iphone14", L"越来", L"越来越",
                                            L"热爱", L"网上",     L"学习", L"happy",
                                            L"work", L"happy",    L"day"};
    ASSERT_EQ(expected, results);
}

TEST(JiebaTokenizerTest, TestNormalizeCase) {
    std::string alphanumeric_term = "THIS123";
    JiebaTokenizer::NormalizeCase(&alphanumeric_term);
    ASSERT_EQ(alphanumeric_term, "this123");

    std::string mixed_ascii_cjk_term = "B超";
    JiebaTokenizer::NormalizeCase(&mixed_ascii_cjk_term);
    ASSERT_EQ(mixed_ascii_cjk_term, "B超");

    std::string term_with_underscore = "THIS_IS";
    JiebaTokenizer::NormalizeCase(&term_with_underscore);
    ASSERT_EQ(term_with_underscore, "THIS_IS");

    std::string chinese_term = "机器";
    JiebaTokenizer::NormalizeCase(&chinese_term);
    ASSERT_EQ(chinese_term, "机器");
}

INSTANTIATE_TEST_SUITE_P(ReadBufferSize, JiebaAnalyzerTest,
                         ::testing::ValuesIn(std::vector<int32_t>({2, 5, 10, 100})));

}  // namespace paimon::lucene::test
