require "../completion_provider"

module Lattice
  module Completion
    module Providers
      # KeywordsProvider supplies Crystal language keywords, built-in types,
      # and common top-level macros as completion items.
      #
      # This provider consolidates the static keyword list that previously lived
      # in `CrystalParser` so it can be composed with other providers cleanly.
      class KeywordsProvider < CompletionProvider
        KEYWORDS = %w[
          abstract alias annotation as as? asm begin break case class
          def do else elsif end ensure enum extend false for fun if
          in include instance_sizeof is_a? lib macro module next nil
          nil? of out pointerof private protected require rescue responds_to?
          return select self sizeof struct super then true type typeof
          uninitialized union unless until verbatim when while with yield
        ]

        BUILTIN_TYPES = %w[
          Array Bool Char Channel Deque Enum Float32 Float64 Hash
          IO Int8 Int16 Int32 Int64 Int128 Iterator Module Nil Number
          Object Pointer Proc Range Regex Set StaticArray String
          Symbol Tuple UInt8 UInt16 UInt32 UInt64 UInt128 Union Void
        ]

        COMMON_MACROS = %w[
          p p! pp pp! puts print raise record delegate forward_missing_to
          getter setter property class_getter class_setter class_property
          getter? setter? property? protected_getter protected_setter
        ]

        KEYWORD_DOCS = {
          "abstract"        => "Declare an abstract class, struct, or method that must be implemented by subclasses.",
          "alias"           => "Create an alias for an existing type.",
          "annotation"      => "Define a custom annotation that can be applied to methods, classes, or instance variables.",
          "as"              => "Cast an expression to a specific type (raises if incompatible).",
          "as?"             => "Cast an expression to a type, returning nil if incompatible.",
          "asm"             => "Embed inline assembly code.",
          "begin"           => "Open a begin/rescue/ensure block.",
          "break"           => "Exit the current loop or block early, optionally returning a value.",
          "case"            => "Pattern-match a value against multiple when or in branches.",
          "class"           => "Define a reference type (heap-allocated, mutable).",
          "def"             => "Define a method.",
          "do"              => "Open a do/end block attached to a method call.",
          "else"            => "The fallback branch of an if, unless, case, or rescue.",
          "elsif"           => "An additional conditional branch inside an if expression.",
          "end"             => "Close a block, method, class, module, or other compound statement.",
          "ensure"          => "A block that always runs after a begin/rescue, even if an exception was raised.",
          "enum"            => "Define an enumeration of named integer constants.",
          "extend"          => "Mix a module's methods in as class-level (singleton) methods.",
          "false"           => "The boolean false literal.",
          "for"             => "Macro-only iteration keyword.",
          "fun"             => "Declare a binding to a C function inside a lib block.",
          "if"              => "Conditional expression — executes the then branch when the condition is truthy.",
          "in"              => "Exhaustive case branch that matches a specific type.",
          "include"         => "Mix a module's instance methods into the current class or module.",
          "instance_sizeof" => "Return the byte size of an instance of a type at compile time.",
          "is_a?"           => "Check whether a value is an instance of a specific type.",
          "lib"             => "Open a C-binding namespace.",
          "macro"           => "Define a macro that runs at compile time.",
          "module"          => "Define a mixin or namespace.",
          "next"            => "Skip the rest of the current iteration and continue with the next one.",
          "nil"             => "The nil literal — the only value of type Nil.",
          "nil?"            => "Return true if the receiver is nil.",
          "of"              => "Specify the element type of an empty array or hash literal.",
          "out"             => "Pass a variable by reference to a C function (fills the value on return).",
          "pointerof"       => "Return a pointer to a variable.",
          "private"         => "Restrict method or constant visibility to the current type.",
          "protected"       => "Restrict method visibility to the current type and its subclasses.",
          "require"         => "Load another Crystal source file or shard.",
          "rescue"          => "Catch an exception raised in the preceding begin or method body.",
          "responds_to?"    => "Check whether a value responds to a given method name.",
          "return"          => "Exit the current method, optionally returning a value.",
          "select"          => "Wait on the first ready channel operation among multiple when branches.",
          "self"            => "Refer to the current object (the receiver of the enclosing method).",
          "sizeof"          => "Return the byte size of a type at compile time.",
          "struct"          => "Define a value type (stack-allocated, immutable by default).",
          "super"           => "Call the same method on the superclass.",
          "then"            => "Separator between a conditional guard and its body (single-line if).",
          "true"            => "The boolean true literal.",
          "type"            => "Declare a C type alias inside a lib block.",
          "typeof"          => "Return the compile-time type of an expression.",
          "uninitialized"   => "Declare a variable without initialising it (unsafe — use with care).",
          "union"           => "Declare a C union inside a lib block.",
          "unless"          => "Conditional expression — executes the then branch when the condition is falsy.",
          "until"           => "Loop while the condition is falsy.",
          "verbatim"        => "Macro keyword: emit the block body without macro expansion.",
          "when"            => "A branch in a case expression.",
          "while"           => "Loop while the condition is truthy.",
          "with"            => "Set the default receiver inside a yield block.",
          "yield"           => "Pass control to the block provided by the caller.",
        } of String => String

        BUILTIN_TYPE_DOCS = {
          "Array"       => "A resizable, ordered list of elements of a single type.",
          "Bool"        => "The boolean type: true or false.",
          "Char"        => "A single Unicode code point.",
          "Channel"     => "A typed, fiber-safe communication channel (buffered or unbuffered).",
          "Deque"       => "A double-ended queue with O(1) push/pop at both ends.",
          "Enum"        => "Base type for all Crystal enumerations.",
          "Float32"     => "A 32-bit IEEE 754 floating-point number.",
          "Float64"     => "A 64-bit IEEE 754 floating-point number (the default float type).",
          "Hash"        => "A mapping from keys to values.",
          "IO"          => "The base type for all input/output streams.",
          "Int8"        => "A signed 8-bit integer (-128..127).",
          "Int16"       => "A signed 16-bit integer.",
          "Int32"       => "A signed 32-bit integer (the default integer type).",
          "Int64"       => "A signed 64-bit integer.",
          "Int128"      => "A signed 128-bit integer.",
          "Iterator"    => "Lazy iteration protocol — values are produced on demand.",
          "Module"      => "Base type for all Crystal modules.",
          "Nil"         => "The type of nil — a type with exactly one value.",
          "Number"      => "Abstract base for all numeric types.",
          "Object"      => "The root of the Crystal type hierarchy.",
          "Pointer"     => "A raw, unsafe pointer to a value in memory.",
          "Proc"        => "A callable object (closure or function reference).",
          "Range"       => "A contiguous sequence of values with a begin and an end.",
          "Regex"       => "A compiled regular expression.",
          "Set"         => "An unordered collection of unique values.",
          "StaticArray" => "A fixed-size, stack-allocated array.",
          "String"      => "An immutable sequence of UTF-8 bytes.",
          "Symbol"      => "An interned, compile-time constant identifier (`:foo`).",
          "Tuple"       => "A fixed-length, heterogeneous, immutable sequence.",
          "UInt8"       => "An unsigned 8-bit integer (0..255, aka Byte).",
          "UInt16"      => "An unsigned 16-bit integer.",
          "UInt32"      => "An unsigned 32-bit integer.",
          "UInt64"      => "An unsigned 64-bit integer.",
          "UInt128"     => "An unsigned 128-bit integer.",
          "Union"       => "A compile-time union of two or more types (A | B).",
          "Void"        => "The absence of a value — used as a return type for C bindings.",
        } of String => String

        COMMON_MACRO_DOCS = {
          "p"                   => "Print a compact inspect representation of one or more values to STDOUT.",
          "p!"                  => "Print inspect output with the expression source and exit the program (debug helper).",
          "pp"                  => "Pretty-print one or more values to STDOUT with their types.",
          "pp!"                 => "Pretty-print and exit (debug helper).",
          "puts"                => "Print each argument to STDOUT followed by a newline.",
          "print"               => "Print each argument to STDOUT without a trailing newline.",
          "raise"               => "Raise an exception.",
          "record"              => "Macro that generates a compact immutable struct.",
          "delegate"            => "Macro that forwards method calls to a named field.",
          "forward_missing_to" => "Macro that forwards any unknown method call to a named field.",
          "getter"              => "Macro that generates a read-only accessor for an instance variable.",
          "setter"              => "Macro that generates a write-only accessor for an instance variable.",
          "property"            => "Macro that generates both getter and setter for an instance variable.",
          "class_getter"        => "Macro that generates a class-level read-only accessor.",
          "class_setter"        => "Macro that generates a class-level write-only accessor.",
          "class_property"      => "Macro that generates class-level getter and setter.",
          "getter?"             => "Macro that generates a boolean getter that returns true when the value is truthy.",
          "setter?"             => "Macro that generates a boolean setter.",
          "property?"           => "Macro that generates a boolean getter and setter.",
        } of String => String

        def completions(
          uri : String,
          source : String,
          position : ::LSP::Position,
        ) : Array(::LSP::CompletionItem)
          items = [] of ::LSP::CompletionItem

          KEYWORDS.each do |kw|
            item = keyword_item(kw)
            item.doc = KEYWORD_DOCS[kw] if KEYWORD_DOCS.has_key?(kw)
            items << item
          end

          BUILTIN_TYPES.each do |t|
            item = ::LSP::CompletionItem.new(t)
            item.kind = ::LSP::CompletionItemKind::Class
            item.doc = BUILTIN_TYPE_DOCS[t] if BUILTIN_TYPE_DOCS.has_key?(t)
            items << item
          end

          COMMON_MACROS.each do |m|
            item = ::LSP::CompletionItem.new(m)
            item.kind = ::LSP::CompletionItemKind::Function
            item.doc = COMMON_MACRO_DOCS[m] if COMMON_MACRO_DOCS.has_key?(m)
            items << item
          end

          items
        end
      end
    end
  end
end
