require "./inspection"

module Lattice
  module Inspections
    # Flags string interpolations of the form `"#{SOME_CONSTANT}"` when the
    # constant name is all-uppercase (heuristic for a String constant).
    # Interpolating a String constant is a no-op compared to using it directly
    # or concatenating it.
    #
    # Detection strategy: pure regex scan over source lines — no AST walk
    # required.  This keeps the inspection fast and free of parse-failure risk.
    #
    # The pattern matches:
    #   - A string interpolation `"#{ ... }"` (either side of string literal)
    #   - Where the interpolated expression is a bare ALL_CAPS constant,
    #     optionally qualified with `::` (e.g. `MY_CONST` or `My::MODULE_CONST`).
    #
    # Code action: replace `"#{CONST}"` with `CONST` (or concatenate if there
    # is surrounding text).
    class ConstantInInterpolationInspection < Inspection
      # Match `"#{CONSTANT}"` where CONSTANT is an ALL_CAPS identifier
      # (possibly namespace-qualified) and the interpolation is the only
      # content of the string literal.
      LONE_CONST_RE = /"\#\{([A-Z][A-Z0-9_]*(?:::[A-Z][A-Z0-9_]*)*)\}"/

      # Also match constants embedded in a larger string, e.g.
      # `"prefix #{CONST} suffix"` — still no-op for the constant part.
      EMBEDDED_CONST_RE = /\#\{([A-Z][A-Z0-9_]*(?:::[A-Z][A-Z0-9_]*)*)\}/

      def run(
        uri : String,
        source : String,
        lines : Array(String),
        ast : ::Crystal::ASTNode,
      ) : Array(::LSP::Diagnostic)
        diagnostics = [] of ::LSP::Diagnostic

        lines.each_with_index do |line, ln|
          # Skip comment lines.
          stripped = line.lstrip
          next if stripped.starts_with?('#')

          offset = 0
          while m = line.match(EMBEDDED_CONST_RE, offset)
            const_name = m[1]
            col_start  = m.begin(0) || 0
            col_end    = m.end(0)   || col_start + m[0].size
            offset     = col_end

            diagnostics << diagnostic(
              "Constant '#{const_name}' is interpolated as a String — " \
              "if #{const_name} is already a String, use it directly or concatenate",
              ln,
              col_start,
              ln,
              col_end,
              ::LSP::DiagnosticSeverity::Warning,
              "lattice",
            )
          end
        end

        diagnostics
      end
    end
  end
end
