#include <vector>
#include <cctype>
#include <algorithm>
#include "./tsl_keywords.hpp"

namespace tsl
{
    std::vector<KeywordInfo> TslKeywords::keywords_;
    std::unordered_set<std::string> TslKeywords::keyword_set_;
    bool TslKeywords::initialized_ = false;

    const std::vector<KeywordInfo>& TslKeywords::GetAllKeywords()
    {
        InitKeywords();
        return keywords_;
    }

    std::vector<KeywordInfo> TslKeywords::GetKeywordsByCategory(KeywordCategory category)
    {
        InitKeywords();
        std::vector<KeywordInfo> result;

        for (const auto& keyword : keywords_)
            if (keyword.category == category)
                result.push_back(keyword);
        return result;
    }

    std::vector<lsp::protocol::CompletionItem> TslKeywords::GetCompletionItems(const std::string& prefix)
    {
        InitKeywords();
        std::vector<lsp::protocol::CompletionItem> result;
        std::string lower_prefix = ToLowerCase(prefix);

        for (const auto& keyword : keywords_)
        {
            if (prefix.empty() || StartsWith(ToLowerCase(keyword.keyword), lower_prefix))
            {
                lsp::protocol::CompletionItem item;
                item.label = keyword.keyword;
                item.kind = keyword.completion_kind;
                item.detail = keyword.description;
                item.insertText = keyword.keyword;
                result.push_back(item);
            }
        }
        // 按字母顺序排序
        std::sort(result.begin(), result.end(),
                  [](const lsp::protocol::CompletionItem& a, const lsp::protocol::CompletionItem& b) {
            return a.label < b.label;
        });
        return result;
    }

    KeywordCategory TslKeywords::GetKeywordCategory(const std::string& word)
    {
        InitKeywords();
        std::string lower_word = ToLowerCase(word);

        for (const auto& keyword : keywords_)
        {
            if (ToLowerCase(keyword.keyword) == lower_word) {
                return keyword.category;
            }
        }

        // 如果没找到，返回一个默认值（可以考虑抛出异常）
        return KeywordCategory::kProgramStructure;
    }

    void TslKeywords::InitKeywords()
    {
        if (initialized_)
            return;
        keywords_ = {
            // Program Structure
            { "program", KeywordCategory::kProgramStructure, "Program declaration", lsp::protocol::CompletionItemKind::kKeyword },
            { "function", KeywordCategory::kProgramStructure, "Function declaration", lsp::protocol::CompletionItemKind::kFunction },
            { "procedure", KeywordCategory::kProgramStructure, "Procedure declaration", lsp::protocol::CompletionItemKind::kFunction },
            { "unit", KeywordCategory::kProgramStructure, "Unit declaration", lsp::protocol::CompletionItemKind::kModule },
            { "uses", KeywordCategory::kProgramStructure, "Uses clause", lsp::protocol::CompletionItemKind::kKeyword },
            { "implementation", KeywordCategory::kProgramStructure, "Implementation section", lsp::protocol::CompletionItemKind::kKeyword },
            { "interface", KeywordCategory::kProgramStructure, "Interface section", lsp::protocol::CompletionItemKind::kInterface },
            { "initialization", KeywordCategory::kProgramStructure, "Initialization section", lsp::protocol::CompletionItemKind::kKeyword },
            { "finalization", KeywordCategory::kProgramStructure, "Finalization section", lsp::protocol::CompletionItemKind::kKeyword },

            // Data Types
            { "string", KeywordCategory::kDataTypes, "String data type", lsp::protocol::CompletionItemKind::kClass },
            { "integer", KeywordCategory::kDataTypes, "Integer data type", lsp::protocol::CompletionItemKind::kClass },
            { "boolean", KeywordCategory::kDataTypes, "Boolean data type", lsp::protocol::CompletionItemKind::kClass },
            { "int64", KeywordCategory::kDataTypes, "64-bit integer data type", lsp::protocol::CompletionItemKind::kClass },
            { "real", KeywordCategory::kDataTypes, "Real number data type", lsp::protocol::CompletionItemKind::kClass },
            { "array", KeywordCategory::kDataTypes, "Array data type", lsp::protocol::CompletionItemKind::kClass },

            // Class Types
            { "type", KeywordCategory::kClassTypes, "Type declaration", lsp::protocol::CompletionItemKind::kKeyword },
            { "class", KeywordCategory::kClassTypes, "Class declaration", lsp::protocol::CompletionItemKind::kClass },
            { "fakeclass", KeywordCategory::kClassTypes, "Fake class declaration", lsp::protocol::CompletionItemKind::kClass },
            { "new", KeywordCategory::kClassTypes, "Object instantiation", lsp::protocol::CompletionItemKind::kKeyword },

            // Class Modifiers
            { "override", KeywordCategory::kClassModifiers, "Override method", lsp::protocol::CompletionItemKind::kKeyword },
            { "overload", KeywordCategory::kClassModifiers, "Overload method", lsp::protocol::CompletionItemKind::kKeyword },
            { "virtual", KeywordCategory::kClassModifiers, "Virtual method", lsp::protocol::CompletionItemKind::kKeyword },
            { "property", KeywordCategory::kClassModifiers, "Property declaration", lsp::protocol::CompletionItemKind::kProperty },
            { "self", KeywordCategory::kClassModifiers, "Self reference", lsp::protocol::CompletionItemKind::kVariable },
            { "inherited", KeywordCategory::kClassModifiers, "Inherited method call", lsp::protocol::CompletionItemKind::kKeyword },

            // Access Modifiers
            { "public", KeywordCategory::kAccessModifiers, "Public access modifier", lsp::protocol::CompletionItemKind::kKeyword },
            { "protected", KeywordCategory::kAccessModifiers, "Protected access modifier", lsp::protocol::CompletionItemKind::kKeyword },
            { "private", KeywordCategory::kAccessModifiers, "Private access modifier", lsp::protocol::CompletionItemKind::kKeyword },
            { "published", KeywordCategory::kAccessModifiers, "Published access modifier", lsp::protocol::CompletionItemKind::kKeyword },

            // Property Accessors
            { "read", KeywordCategory::kPropertyAccessors, "Property read accessor", lsp::protocol::CompletionItemKind::kKeyword },
            { "write", KeywordCategory::kPropertyAccessors, "Property write accessor", lsp::protocol::CompletionItemKind::kKeyword },

            // Constructors
            { "create", KeywordCategory::kConstructors, "Constructor method", lsp::protocol::CompletionItemKind::kConstructor },
            { "destroy", KeywordCategory::kConstructors, "Destructor method", lsp::protocol::CompletionItemKind::kMethod },
            { "operator", KeywordCategory::kConstructors, "Operator overload", lsp::protocol::CompletionItemKind::kOperator },

            // Variable Modifiers
            { "external", KeywordCategory::kVariableModifiers, "External declaration", lsp::protocol::CompletionItemKind::kKeyword },
            { "const", KeywordCategory::kVariableModifiers, "Constant declaration", lsp::protocol::CompletionItemKind::kConstant },
            { "out", KeywordCategory::kVariableModifiers, "Output parameter", lsp::protocol::CompletionItemKind::kKeyword },
            { "var", KeywordCategory::kVariableModifiers, "Variable declaration", lsp::protocol::CompletionItemKind::kVariable },
            { "global", KeywordCategory::kVariableModifiers, "Global variable", lsp::protocol::CompletionItemKind::kVariable },
            { "static", KeywordCategory::kVariableModifiers, "Static variable", lsp::protocol::CompletionItemKind::kVariable },

            // Conditionals
            { "if", KeywordCategory::kConditionals, "If statement", lsp::protocol::CompletionItemKind::kKeyword },
            { "else", KeywordCategory::kConditionals, "Else clause", lsp::protocol::CompletionItemKind::kKeyword },
            { "then", KeywordCategory::kConditionals, "Then clause", lsp::protocol::CompletionItemKind::kKeyword },
            { "case", KeywordCategory::kConditionals, "Case statement", lsp::protocol::CompletionItemKind::kKeyword },
            { "of", KeywordCategory::kConditionals, "Of clause", lsp::protocol::CompletionItemKind::kKeyword },

            // Loops
            { "for", KeywordCategory::kLoops, "For loop", lsp::protocol::CompletionItemKind::kKeyword },
            { "while", KeywordCategory::kLoops, "While loop", lsp::protocol::CompletionItemKind::kKeyword },
            { "do", KeywordCategory::kLoops, "Do clause", lsp::protocol::CompletionItemKind::kKeyword },
            { "downto", KeywordCategory::kLoops, "Downto clause", lsp::protocol::CompletionItemKind::kKeyword },
            { "step", KeywordCategory::kLoops, "Step clause", lsp::protocol::CompletionItemKind::kKeyword },
            { "until", KeywordCategory::kLoops, "Until clause", lsp::protocol::CompletionItemKind::kKeyword },
            { "repeat", KeywordCategory::kLoops, "Repeat loop", lsp::protocol::CompletionItemKind::kKeyword },
            { "to", KeywordCategory::kLoops, "To clause", lsp::protocol::CompletionItemKind::kKeyword },

            // Branch Control
            { "break", KeywordCategory::kBranchControl, "Break statement", lsp::protocol::CompletionItemKind::kKeyword },
            { "continue", KeywordCategory::kBranchControl, "Continue statement", lsp::protocol::CompletionItemKind::kKeyword },
            { "goto", KeywordCategory::kBranchControl, "Goto statement", lsp::protocol::CompletionItemKind::kKeyword },
            { "label", KeywordCategory::kBranchControl, "Label declaration", lsp::protocol::CompletionItemKind::kKeyword },
            { "exit", KeywordCategory::kBranchControl, "Exit statement", lsp::protocol::CompletionItemKind::kKeyword },

            // Return Control
            { "return", KeywordCategory::kReturnControl, "Return statement", lsp::protocol::CompletionItemKind::kKeyword },
            { "debugreturn", KeywordCategory::kReturnControl, "Debug return statement", lsp::protocol::CompletionItemKind::kKeyword },
            { "debugrunenv", KeywordCategory::kReturnControl, "Debug run environment", lsp::protocol::CompletionItemKind::kKeyword },
            { "debugrunenvdo", KeywordCategory::kReturnControl, "Debug run environment do", lsp::protocol::CompletionItemKind::kKeyword },

            // Block Control
            { "begin", KeywordCategory::kBlockControl, "Begin block", lsp::protocol::CompletionItemKind::kKeyword },
            { "end", KeywordCategory::kBlockControl, "End block", lsp::protocol::CompletionItemKind::kKeyword },
            { "with", KeywordCategory::kBlockControl, "With statement", lsp::protocol::CompletionItemKind::kKeyword },

            // References
            { "weakref", KeywordCategory::kReferences, "Weak reference", lsp::protocol::CompletionItemKind::kKeyword },
            { "autoref", KeywordCategory::kReferences, "Auto reference", lsp::protocol::CompletionItemKind::kKeyword },

            // Namespace
            { "namespace", KeywordCategory::kNamespace, "Namespace declaration", lsp::protocol::CompletionItemKind::kModule },

            // Exceptions
            { "except", KeywordCategory::kExceptions, "Exception handling", lsp::protocol::CompletionItemKind::kKeyword },
            { "raise", KeywordCategory::kExceptions, "Raise exception", lsp::protocol::CompletionItemKind::kKeyword },
            { "try", KeywordCategory::kExceptions, "Try block", lsp::protocol::CompletionItemKind::kKeyword },
            { "finally", KeywordCategory::kExceptions, "Finally block", lsp::protocol::CompletionItemKind::kKeyword },
            { "exceptobject", KeywordCategory::kExceptions, "Exception object", lsp::protocol::CompletionItemKind::kKeyword },

            // Logical Operators
            { "and", KeywordCategory::kLogicalOperators, "Logical AND", lsp::protocol::CompletionItemKind::kOperator },
            { "in", KeywordCategory::kLogicalOperators, "In operator", lsp::protocol::CompletionItemKind::kOperator },
            { "is", KeywordCategory::kLogicalOperators, "Is operator", lsp::protocol::CompletionItemKind::kOperator },
            { "not", KeywordCategory::kLogicalOperators, "Logical NOT", lsp::protocol::CompletionItemKind::kOperator },
            { "or", KeywordCategory::kLogicalOperators, "Logical OR", lsp::protocol::CompletionItemKind::kOperator },

            // Arithmetic Operators
            { "div", KeywordCategory::kArithmeticOperators, "Integer division", lsp::protocol::CompletionItemKind::kOperator },
            { "mod", KeywordCategory::kArithmeticOperators, "Modulo operation", lsp::protocol::CompletionItemKind::kOperator },

            // Bitwise Operators
            { "ror", KeywordCategory::kBitwiseOperators, "Rotate right", lsp::protocol::CompletionItemKind::kOperator },
            { "rol", KeywordCategory::kBitwiseOperators, "Rotate left", lsp::protocol::CompletionItemKind::kOperator },
            { "shr", KeywordCategory::kBitwiseOperators, "Shift right", lsp::protocol::CompletionItemKind::kOperator },
            { "shl", KeywordCategory::kBitwiseOperators, "Shift left", lsp::protocol::CompletionItemKind::kOperator },

            // Set Operators
            { "union", KeywordCategory::kSetOperators, "Set union", lsp::protocol::CompletionItemKind::kOperator },
            { "minus", KeywordCategory::kSetOperators, "Set difference", lsp::protocol::CompletionItemKind::kOperator },
            { "union2", KeywordCategory::kSetOperators, "Set union (alternative)", lsp::protocol::CompletionItemKind::kOperator },

            // SQL Control
            { "select", KeywordCategory::kSqlControl, "SQL SELECT", lsp::protocol::CompletionItemKind::kKeyword },
            { "vselect", KeywordCategory::kSqlControl, "Virtual SELECT", lsp::protocol::CompletionItemKind::kKeyword },
            { "sselect", KeywordCategory::kSqlControl, "Special SELECT", lsp::protocol::CompletionItemKind::kKeyword },
            { "update", KeywordCategory::kSqlControl, "SQL UPDATE", lsp::protocol::CompletionItemKind::kKeyword },
            { "delete", KeywordCategory::kSqlControl, "SQL DELETE", lsp::protocol::CompletionItemKind::kKeyword },
            { "mselect", KeywordCategory::kSqlControl, "Multiple SELECT", lsp::protocol::CompletionItemKind::kKeyword },

            // SQL Keywords
            { "sqlin", KeywordCategory::kSqlKeywords, "SQL IN", lsp::protocol::CompletionItemKind::kKeyword },
            { "from", KeywordCategory::kSqlKeywords, "SQL FROM", lsp::protocol::CompletionItemKind::kKeyword },
            { "where", KeywordCategory::kSqlKeywords, "SQL WHERE", lsp::protocol::CompletionItemKind::kKeyword },
            { "group", KeywordCategory::kSqlKeywords, "SQL GROUP", lsp::protocol::CompletionItemKind::kKeyword },
            { "by", KeywordCategory::kSqlKeywords, "SQL BY", lsp::protocol::CompletionItemKind::kKeyword },
            { "order", KeywordCategory::kSqlKeywords, "SQL ORDER", lsp::protocol::CompletionItemKind::kKeyword },
            { "distinct", KeywordCategory::kSqlKeywords, "SQL DISTINCT", lsp::protocol::CompletionItemKind::kKeyword },
            { "join", KeywordCategory::kSqlKeywords, "SQL JOIN", lsp::protocol::CompletionItemKind::kKeyword },

            // SQL Operators (note: some overlap with logical operators)
            { "on", KeywordCategory::kSqlOperators, "SQL ON", lsp::protocol::CompletionItemKind::kOperator },
            { "like", KeywordCategory::kSqlOperators, "SQL LIKE", lsp::protocol::CompletionItemKind::kOperator },

            // Calling Conventions
            { "cdecl", KeywordCategory::kCallingConventions, "C calling convention", lsp::protocol::CompletionItemKind::kKeyword },
            { "pascal", KeywordCategory::kCallingConventions, "Pascal calling convention", lsp::protocol::CompletionItemKind::kKeyword },
            { "stdcall", KeywordCategory::kCallingConventions, "Standard calling convention", lsp::protocol::CompletionItemKind::kKeyword },
            { "safecall", KeywordCategory::kCallingConventions, "Safe calling convention", lsp::protocol::CompletionItemKind::kKeyword },
            { "fastcall", KeywordCategory::kCallingConventions, "Fast calling convention", lsp::protocol::CompletionItemKind::kKeyword },
            { "register", KeywordCategory::kCallingConventions, "Register calling convention", lsp::protocol::CompletionItemKind::kKeyword },

            // System Keywords
            { "setuid", KeywordCategory::kSystemKeywords, "Set user ID", lsp::protocol::CompletionItemKind::kKeyword },
            { "sudo", KeywordCategory::kSystemKeywords, "Super user do", lsp::protocol::CompletionItemKind::kKeyword },

            // Builtin Variables
            { "paramcount", KeywordCategory::kBuiltinVariables, "Parameter count", lsp::protocol::CompletionItemKind::kVariable },
            { "realparamcount", KeywordCategory::kBuiltinVariables, "Real parameter count", lsp::protocol::CompletionItemKind::kVariable },
            { "params", KeywordCategory::kBuiltinVariables, "Parameters array", lsp::protocol::CompletionItemKind::kVariable },
            { "system", KeywordCategory::kBuiltinVariables, "System variable", lsp::protocol::CompletionItemKind::kVariable },
            { "tslassigning", KeywordCategory::kBuiltinVariables, "TSL assigning", lsp::protocol::CompletionItemKind::kVariable },
            { "likeeps", KeywordCategory::kBuiltinVariables, "Like EPS", lsp::protocol::CompletionItemKind::kVariable },
            { "likeepsrate", KeywordCategory::kBuiltinVariables, "Like EPS rate", lsp::protocol::CompletionItemKind::kVariable },

            // Builtin Functions
            { "echo", KeywordCategory::kBuiltinFunctions, "Echo function", lsp::protocol::CompletionItemKind::kFunction },
            { "mtic", KeywordCategory::kBuiltinFunctions, "MTIC function", lsp::protocol::CompletionItemKind::kFunction },
            { "mtoc", KeywordCategory::kBuiltinFunctions, "MTOC function", lsp::protocol::CompletionItemKind::kFunction },

            // Boolean Constants
            { "false", KeywordCategory::kBooleanConstants, "Boolean false", lsp::protocol::CompletionItemKind::kConstant },
            { "true", KeywordCategory::kBooleanConstants, "Boolean true", lsp::protocol::CompletionItemKind::kConstant },

            // Math Constants
            { "inf", KeywordCategory::kMathConstants, "Infinity", lsp::protocol::CompletionItemKind::kConstant },
            { "nan", KeywordCategory::kMathConstants, "Not a Number", lsp::protocol::CompletionItemKind::kConstant },

            // Null Constants
            { "nil", KeywordCategory::kNullConstants, "Null value", lsp::protocol::CompletionItemKind::kConstant }
        };
        keyword_set_.clear();
        for (const auto& keyword : keywords_)
            keyword_set_.insert(ToLowerCase(keyword.keyword));
        initialized_ = true;
    }

    std::string TslKeywords::ToLowerCase(const std::string& str)
    {
        std::string result = str;
        std::transform(result.begin(), result.end(), result.begin(), ::tolower);
        return result;
    }

    bool TslKeywords::StartsWith(const std::string& str, const std::string& prefix)
    {
        if (prefix.length() > str.length())
            return false;
        return str.compare(0, prefix.length(), prefix) == 0;
    }
}
