// 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 "runtime/runtime_predicate.h"

#include <memory>

#include "common/compiler_util.h" // IWYU pragma: keep
#include "common/exception.h"
#include "common/status.h"
#include "core/data_type/define_primitive_type.h"
#include "storage/predicate/accept_null_predicate.h"
#include "storage/predicate/column_predicate.h"
#include "storage/predicate/predicate_creator.h"

namespace doris {

RuntimePredicate::RuntimePredicate(const TTopnFilterDesc& desc)
        : _nulls_first(desc.null_first), _is_asc(desc.is_asc) {
    DCHECK(!desc.target_node_id_to_target_expr.empty());
    for (auto p : desc.target_node_id_to_target_expr) {
        _contexts[p.first].expr = p.second;
    }

    _type = thrift_to_type(desc.target_node_id_to_target_expr.begin()
                                   ->second.nodes[0]
                                   .type.types[0]
                                   .scalar_type.type);
    if (!_init(_type)) {
        std::stringstream ss;
        desc.target_node_id_to_target_expr.begin()->second.nodes[0].printTo(ss);
        throw Exception(ErrorCode::INTERNAL_ERROR, "meet invalid type, type={}, expr={}",
                        type_to_string(_type), ss.str());
    }

    // For ASC  sort, create runtime predicate col_name <= max_top_value
    // since values that > min_top_value are large than any value in current topn values
    // For DESC sort, create runtime predicate col_name >= min_top_value
    // since values that < min_top_value are less than any value in current topn values
    _pred_constructor = _is_asc ? create_comparison_predicate<PredicateType::LE>
                                : create_comparison_predicate<PredicateType::GE>;
}

Status RuntimePredicate::init_target(
        int32_t target_node_id, phmap::flat_hash_map<int, SlotDescriptor*> slot_id_to_slot_desc,
        const int column_id) {
    if (column_id < 0) {
        _detected_target = true;
        return Status::OK();
    }
    std::unique_lock<std::shared_mutex> wlock(_rwlock);
    check_target_node_id(target_node_id);
    // order by abs(col1) limit x;
    // cannot be used min-max filter, no need create predicate.
    // but can used in VTopNPred.execute_column
    if (target_is_slot(target_node_id)) {
        _contexts[target_node_id].col_name =
                slot_id_to_slot_desc[get_texpr(target_node_id).nodes[0].slot_ref.slot_id]
                        ->col_name();
        _contexts[target_node_id].col_data_type =
                slot_id_to_slot_desc[get_texpr(target_node_id).nodes[0].slot_ref.slot_id]->type();
        _contexts[target_node_id].predicate = SharedPredicate::create_shared(
                cast_set<uint32_t>(column_id), _contexts[target_node_id].col_name);
    }
    _detected_target = true;
    return Status::OK();
}

bool RuntimePredicate::_init(PrimitiveType type) {
    return is_int_or_bool(type) || is_decimal(type) || is_string_type(type) || is_date_type(type) ||
           is_timestamp_ns_type(type) || is_time_type(type) || is_timestamptz_type(type) ||
           is_ip(type) || is_varbinary(type);
}

Status RuntimePredicate::update(const Field& value) {
    std::unique_lock<std::shared_mutex> wlock(_rwlock);
    // skip null value
    if (value.is_null()) {
        return Status::OK();
    }

    bool updated = false;

    if (UNLIKELY(_orderby_extrem.is_null())) {
        _orderby_extrem = value;
        updated = true;
    } else {
        if ((_is_asc && value < _orderby_extrem) || (!_is_asc && value > _orderby_extrem)) {
            _orderby_extrem = value;
            updated = true;
        }
    }

    _has_value = true;

    if (!updated) {
        return Status::OK();
    }
    for (auto p : _contexts) {
        auto ctx = p.second;
        if (ctx.predicate == nullptr) {
            // 1. `init_target` will not create predicate. example : `order by abs(col1) limit x;`
            // So don't need create new `ColumnPredicate`,
            // but need update `_orderby_extrem` for  `VTopNPred.execute_column`
            // 2. this `RuntimePredicate` will associate multiple scan nodes.
            // When the sort node is updated, some scan nodes may not have called `init_target` yet.
            // example:
            //SELECT subq1.pk AS pk1 FROM (
            //    ( SELECT t1.pk  FROM tb AS t1 )
            //    UNION ALL
            //    ( SELECT t1.pk  FROM tb AS t1  ORDER BY t1.pk ))
            //    subq1
            //WHERE subq1.pk <> (
            //    SELECT t1.pk  FROM tb AS t1  ORDER BY t1.pk LIMIT 1
            //) ORDER BY 1 LIMIT 1 ;
            continue;
        }
        std::shared_ptr<ColumnPredicate> pred =
                _pred_constructor(ctx.predicate->column_id(), ctx.col_name, ctx.col_data_type,
                                  _orderby_extrem, false);

        // For NULLS FIRST, wrap a AcceptNullPredicate to return true for NULL
        // since ORDER BY ASC/DESC should get NULL first but pred returns NULL
        // and NULL in where predicate will be treated as FALSE
        if (_nulls_first) {
            pred = AcceptNullPredicate::create_shared(pred);
        }

        ((SharedPredicate*)ctx.predicate.get())->set_nested(pred);
    }
    return Status::OK();
}

} // namespace doris
