require "../completion_provider"
require "../../index/index"

module Lattice
  module Completion
    module Providers
      # StructLiteralProvider offers field-name completions after `TypeName{`
      # or `TypeName.new(` syntax, using the workspace index to resolve the
      # struct/class definition and extract its named fields.
      class StructLiteralProvider < CompletionProvider
        def initialize(@index : Lattice::Index::WorkspaceIndex)
        end

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

          lines = source.split('\n')
          return items if position.line >= lines.size

          line = lines[position.line]
          col = position.character.clamp(0, line.size)
          prefix = line[0...col]

          # Detect `TypeName{` or `TypeName.new(` with optional preceding whitespace.
          type_name = extract_type_before_brace(prefix)
          return items unless type_name

          # Look up field-like symbols for this type from the index.
          @index.all_of_kind("property").each do |entry|
            next unless entry.name.starts_with?("#{type_name}::@") ||
                        entry.name.starts_with?("#{type_name}::")
            field = entry.name.split("::").last.lstrip('@')
            i = field_item(field, entry.type_name)
            i.insert_text = "#{field}: "
            if doc = entry.documentation
              i.doc = doc
            end
            items << i
          end

          @index.all_of_kind("instance_variable").each do |entry|
            next unless entry.name.starts_with?("#{type_name}::@")
            field = entry.name.split("::").last.lstrip('@')
            next if items.any? { |i| i.label == field }
            i = field_item(field, entry.type_name)
            i.insert_text = "#{field}: "
            items << i
          end

          items
        end

        # Returns the type name immediately before `{` or `.new(` at the end of
        # *prefix*, or nil if the pattern is not matched.
        private def extract_type_before_brace(prefix : String) : String?
          if m = prefix.rstrip.match(/([A-Z]\w*)\s*\{\s*$/)
            return m[1]
          end
          if m = prefix.rstrip.match(/([A-Z]\w*)\.new\s*\(\s*$/)
            return m[1]
          end
          nil
        end
      end
    end
  end
end
