/*
 * 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 "common/device_id.h"

#include <algorithm>
#include <cctype>
#include <numeric>
#include <stdexcept>
#include <unordered_set>

#include "constant/tsfile_constant.h"
#ifdef ENABLE_ANTLR4
#include "parser/path_nodes_generator.h"
#endif
#include "utils/errno_define.h"

namespace storage {

// IDeviceID implementation
IDeviceID::IDeviceID() : empty_segments_() {}

int IDeviceID::serialize(common::ByteStream& write_stream) { return 0; }
int IDeviceID::deserialize(common::ByteStream& read_stream) { return 0; }
std::string IDeviceID::get_table_name() { return ""; }
int IDeviceID::segment_num() { return 0; }
const std::vector<std::string*>& IDeviceID::get_segments() const {
    return empty_segments_;
}
std::string IDeviceID::get_device_name() const { return ""; }
bool IDeviceID::operator<(const IDeviceID& other) { return false; }
bool IDeviceID::operator==(const IDeviceID& other) { return false; }
bool IDeviceID::operator!=(const IDeviceID& other) { return false; }

// IDeviceIDComparator implementation
bool IDeviceIDComparator::operator()(
    const std::shared_ptr<IDeviceID>& lhs,
    const std::shared_ptr<IDeviceID>& rhs) const {
    return *lhs < *rhs;
}

// StringArrayDeviceID implementation
StringArrayDeviceID::StringArrayDeviceID(
    const std::vector<std::string>& segments)
    : segments_(formalize(segments)) {}

StringArrayDeviceID::StringArrayDeviceID(const std::string& device_id_string) {
    auto segments = split_device_id_string(device_id_string);
    segments_.reserve(segments.size());
    for (const auto& segment : segments) {
        segments_.push_back(new std::string(segment));
    }
}

StringArrayDeviceID::StringArrayDeviceID(
    const std::vector<std::string*>& segments) {
    segments_.reserve(segments.size());
    for (const auto& segment : segments) {
        segments_.push_back(segment == nullptr ? nullptr
                                               : new std::string(*segment));
    }
}

StringArrayDeviceID::StringArrayDeviceID() : segments_() {}

StringArrayDeviceID::~StringArrayDeviceID() {
    for (const auto& segment : segments_) {
        delete segment;
    }
    for (const auto& prefix_segments : prefix_segments_) {
        delete prefix_segments;
    }
}

std::string StringArrayDeviceID::get_device_name() const {
    if (segments_.empty()) {
        return "";
    }
    // Builds device name by concatenating segments with '.' delimiter,
    // handling null segments by replacing them with "null"
    return std::accumulate(std::next(segments_.begin()), segments_.end(),
                           segments_.front() ? *segments_.front() : "null",
                           [](std::string acc, const std::string* segment) {
                               return std::move(acc) + "." +
                                      (segment ? *segment : "null");
                           });
}

void StringArrayDeviceID::init_prefix_segments() {
    // Idempotent: device IDs are cached and reused across queries, so clear
    // previous prefixes before rebuilding to avoid accumulation and leaks.
    for (const auto& prefix_segment : prefix_segments_) {
        delete prefix_segment;
    }
    prefix_segments_.clear();

#ifdef ENABLE_ANTLR4
    auto splits = storage::PathNodesGenerator::invokeParser(*segments_[0]);
#else
    auto splits = split_string(*segments_[0], '.');
#endif
    for (int i = 0; i < splits.size(); ++i) {
        prefix_segments_.push_back(new std::string(splits[i]));
    }
}

int StringArrayDeviceID::serialize(common::ByteStream& write_stream) {
    int ret = common::E_OK;
    if (RET_FAIL(common::SerializationUtil::write_var_uint(segment_num(),
                                                           write_stream))) {
        return ret;
    }
    for (const auto& segment : segments_) {
        if (RET_FAIL(common::SerializationUtil::write_var_char_ptr(
                segment, write_stream))) {
            return ret;
        }
    }
    return ret;
}

int StringArrayDeviceID::deserialize(common::ByteStream& read_stream) {
    int ret = common::E_OK;

    uint32_t num_segments;
    if (RET_FAIL(common::SerializationUtil::read_var_uint(num_segments,
                                                          read_stream))) {
        return ret;
    }

    for (auto& segment : segments_) {
        if (segment != nullptr) {
            delete segment;
        }
    }

    segments_.clear();
    for (uint32_t i = 0; i < num_segments; ++i) {
        std::string* segment = nullptr;
        if (RET_FAIL(common::SerializationUtil::read_var_char_ptr(
                segment, read_stream))) {
            delete segment;
            return ret;
        }
        segments_.push_back(segment);
    }
    return ret;
}

std::string StringArrayDeviceID::get_table_name() {
    return segments_.empty() ? "" : *segments_[0];
}

int StringArrayDeviceID::segment_num() {
    return static_cast<int>(segments_.size());
}

const std::vector<std::string*>& StringArrayDeviceID::get_segments() const {
    return segments_;
}

bool StringArrayDeviceID::operator<(const IDeviceID& other) {
    auto other_segments = other.get_segments();
    return std::lexicographical_compare(
        segments_.begin(), segments_.end(), other_segments.begin(),
        other_segments.end(), [](const std::string* a, const std::string* b) {
            if (a == nullptr && b == nullptr) return false;  // equal
            if (a == nullptr) return true;   // nullptr < any string
            if (b == nullptr) return false;  // any string > nullptr
            return *a < *b;
        });
}

bool StringArrayDeviceID::operator==(const IDeviceID& other) {
    auto other_segments = other.get_segments();
    return (segments_.size() == other_segments.size()) &&
           std::equal(segments_.begin(), segments_.end(),
                      other_segments.begin(),
                      [](const std::string* a, const std::string* b) {
                          if (a == nullptr && b == nullptr) return true;
                          if (a == nullptr || b == nullptr) return false;
                          return *a == *b;
                      });
}

bool StringArrayDeviceID::operator!=(const IDeviceID& other) {
    return !(*this == other);
}

std::vector<std::string*> StringArrayDeviceID::formalize(
    const std::vector<std::string>& segments) {
    std::vector<std::string*> result;
    result.reserve(segments.size());
    for (const auto& segment : segments) {
        result.emplace_back(new std::string(segment));
    }
    return result;
}

std::vector<std::string> StringArrayDeviceID::split_device_id_string(
    const std::string& device_id_string) {
#ifdef ENABLE_ANTLR4
    auto splits = storage::PathNodesGenerator::invokeParser(device_id_string);
#else
    auto splits = split_string(device_id_string, '.');
#endif
    return split_device_id_string(splits);
}

std::vector<std::string> StringArrayDeviceID::split_device_id_string(
    const std::vector<std::string>& splits) {
    size_t segment_cnt = splits.size();
    std::vector<std::string> final_segments;

    if (segment_cnt == 0) {
        return final_segments;
    }

    if (segment_cnt == 1) {
        // "root" -> {"root"}
        final_segments.push_back(splits[0]);
    } else if (segment_cnt <
               static_cast<size_t>(storage::DEFAULT_SEGMENT_NUM_FOR_TABLE_NAME +
                                   1)) {
        // "root.a" -> {"root", "a"}
        // "root.a.b" -> {"root.a", "b"}
        std::string table_name = std::accumulate(
            splits.begin(), splits.end() - 1, std::string(),
            [](const std::string& a, const std::string& b) {
                return a.empty() ? b : a + storage::PATH_SEPARATOR + b;
            });
        final_segments.push_back(table_name);
        final_segments.push_back(splits.back());
    } else {
        // "root.a.b.c" -> {"root.a.b", "c"}
        // "root.a.b.c.d" -> {"root.a.b", "c", "d"}
        std::string table_name = std::accumulate(
            splits.begin(),
            splits.begin() + storage::DEFAULT_SEGMENT_NUM_FOR_TABLE_NAME,
            std::string(), [](const std::string& a, const std::string& b) {
                return a.empty() ? b : a + storage::PATH_SEPARATOR + b;
            });

        final_segments.emplace_back(std::move(table_name));
        final_segments.insert(
            final_segments.end(),
            splits.begin() + storage::DEFAULT_SEGMENT_NUM_FOR_TABLE_NAME,
            splits.end());
    }

    return final_segments;
}

std::vector<std::string> IDeviceID::split_string(const std::string& str,
                                                 char delimiter) {
    std::vector<std::string> tokens;

    // Reject newlines in path explicitly (illegal path name).
    if (str.find('\n') != std::string::npos ||
        str.find('\r') != std::string::npos) {
        throw std::runtime_error("Path contains newline");
    }

    std::string token;
    bool in_back_quotes = false;    // Inside `quoted` section
    bool in_double_quotes = false;  // Inside "quoted" section
    bool in_single_quotes = false;  // Inside 'quoted' section

    for (size_t i = 0; i < str.length(); ++i) {
        char c = str[i];

        // Toggle quote state when encountering a quote character outside other
        // quote types.
        if (c == '`' && !in_double_quotes && !in_single_quotes) {
            in_back_quotes = !in_back_quotes;
            token += c;  // preserve the backtick character
        } else if (c == '"' && !in_back_quotes && !in_single_quotes) {
            in_double_quotes = !in_double_quotes;
            token += c;  // preserve
        } else if (c == '\'' && !in_back_quotes && !in_double_quotes) {
            in_single_quotes = !in_single_quotes;
            token += c;  // preserve
        } else if (c == delimiter && !in_back_quotes && !in_double_quotes &&
                   !in_single_quotes) {
            // delimiter outside quotes -> split
            if (!token.empty()) {
                validate_identifier(token);
                tokens.push_back(unquote_identifier(token));
                token.clear();
            } else {
                tokens.push_back(token);
                token.clear();
            }
        } else {
            // preserve all characters verbatim (including backslashes and
            // doubled backticks)
            token += c;
        }
    }

    // Unmatched quotes are errors
    if (in_back_quotes || in_double_quotes || in_single_quotes) {
        throw std::runtime_error("Unmatched quotes in path");
    }

    // Add the last token if non-empty (mirror original behaviour)
    if (!token.empty()) {
        validate_identifier(token);
        tokens.push_back(unquote_identifier(token));
    }

    return tokens;
}

std::string IDeviceID::unquote_identifier(const std::string& identifier) {
    if (identifier.length() >= 2) {
        char first = identifier.front();
        char last = identifier.back();

        if ((first == '`' && last == '`') || (first == '"' && last == '"') ||
            (first == '\'' && last == '\'')) {
            std::string inner = identifier.substr(1, identifier.length() - 2);

            // Lowercase copy for case-insensitive comparison
            std::string lower_inner = inner;
            std::transform(lower_inner.begin(), lower_inner.end(),
                           lower_inner.begin(),
                           [](unsigned char ch) { return std::tolower(ch); });

            static const std::unordered_set<std::string> keywords = {
                "select", "device", "drop_trigger", "and",
                "or",     "not",    "null",         "contains"};

            // If the identifier is enclosed in backticks AND inner is a
            // keyword, unquote it (testcase: `select` -> select)
            if (first == '`' && keywords.find(lower_inner) != keywords.end()) {
                return inner;
            }

            // Otherwise: keep original quoting
        }
    }

    return identifier;
}

void IDeviceID::validate_identifier(const std::string& identifier) {
    if (identifier.empty()) return;

    bool quoted = (identifier.size() >= 2 &&
                   ((identifier.front() == '`' && identifier.back() == '`') ||
                    (identifier.front() == '"' && identifier.back() == '"') ||
                    (identifier.front() == '\'' && identifier.back() == '\'')));

    if (quoted) return;  // quoted identifiers are always accepted

    // 1. Pure digits - unquoted numeric literals not allowed as identifiers
    bool all_digits = true;
    for (char c : identifier) {
        if (!std::isdigit((unsigned char)c)) {
            all_digits = false;
            break;
        }
    }
    if (all_digits) {
        throw std::runtime_error("Unquoted pure digits are illegal");
    }

    // 2. Numeric-like illegal patterns (e.g., 0e38, 00.12 not allowed unquoted)
    if (!identifier.empty() && std::isdigit((unsigned char)identifier[0])) {
        throw std::runtime_error("Identifier cannot start with a digit");
    }

    // 3. Illegal wildcards in unquoted identifiers
    if (identifier.find('%') != std::string::npos) {
        throw std::runtime_error("Illegal wildcard in unquoted identifier");
    }

    // 4. Asterisk (*) validation: if present, must consist only of asterisks
    if (identifier.find('*') != std::string::npos) {
        // Check if all characters are asterisks
        bool all_asterisks = true;
        for (char c : identifier) {
            if (c != '*') {
                all_asterisks = false;
                break;
            }
        }
        if (!all_asterisks) {
            throw std::runtime_error(
                "Asterisk wildcard must be the only character type");
        }
    }
}

}  // namespace storage