module Sass
  module Selector
    # A comma-separated sequence of selectors.
    class CommaSequence < AbstractSequence
      @@compound_extend_deprecation = Sass::Deprecation.new

      # The comma-separated selector sequences
      # represented by this class.
      #
      # @return [Array<Sequence>]
      attr_reader :members

      # @param seqs [Array<Sequence>] See \{#members}
      def initialize(seqs)
        @members = seqs
      end

      # Resolves the {Parent} selectors within this selector
      # by replacing them with the given parent selector,
      # handling commas appropriately.
      #
      # @param super_cseq [CommaSequence] The parent selector
      # @param implicit_parent [Boolean] Whether the the parent
      #   selector should automatically be prepended to the resolved
      #   selector if it contains no parent refs.
      # @return [CommaSequence] This selector, with parent references resolved
      # @raise [Sass::SyntaxError] If a parent selector is invalid
      def resolve_parent_refs(super_cseq, implicit_parent = true)
        if super_cseq.nil?
          if contains_parent_ref?
            raise Sass::SyntaxError.new(
              "Base-level rules cannot contain the parent-selector-referencing character '&'.")
          end
          return self
        end

        CommaSequence.new(Sass::Util.flatten_vertically(@members.map do |seq|
          seq.resolve_parent_refs(super_cseq, implicit_parent).members
        end))
      end

      # Returns whether there's a {Parent} selector anywhere in this sequence.
      #
      # @return [Boolean]
      def contains_parent_ref?
        @members.any? {|sel| sel.contains_parent_ref?}
      end

      # Non-destrucively extends this selector with the extensions specified in a hash
      # (which should come from {Sass::Tree::Visitors::Cssize}).
      #
      # @todo Link this to the reference documentation on `@extend`
      #   when such a thing exists.
      #
      # @param extends [Sass::Util::SubsetMap{Selector::Simple =>
      #                                       Sass::Tree::Visitors::Cssize::Extend}]
      #   The extensions to perform on this selector
      # @param parent_directives [Array<Sass::Tree::DirectiveNode>]
      #   The directives containing this selector.
      # @param replace [Boolean]
      #   Whether to replace the original selector entirely or include
      #   it in the result.
      # @param seen [Set<Array<Selector::Simple>>]
      #   The set of simple sequences that are currently being replaced.
      # @param original [Boolean]
      #   Whether this is the original selector being extended, as opposed to
      #   the result of a previous extension that's being re-extended.
      # @return [CommaSequence] A copy of this selector,
      #   with extensions made according to `extends`
      def do_extend(extends, parent_directives = [], replace = false, seen = Set.new,
          original = true)
        CommaSequence.new(members.map do |seq|
          seq.do_extend(extends, parent_directives, replace, seen, original)
        end.flatten)
      end

      # Returns whether or not this selector matches all elements
      # that the given selector matches (as well as possibly more).
      #
      # @example
      #   (.foo).superselector?(.foo.bar) #=> true
      #   (.foo).superselector?(.bar) #=> false
      # @param cseq [CommaSequence]
      # @return [Boolean]
      def superselector?(cseq)
        cseq.members.all? {|seq1| members.any? {|seq2| seq2.superselector?(seq1)}}
      end

      # Populates a subset map that can then be used to extend
      # selectors. This registers an extension with this selector as
      # the extender and `extendee` as the extendee.
      #
      # @param extends [Sass::Util::SubsetMap{Selector::Simple =>
      #                                       Sass::Tree::Visitors::Cssize::Extend}]
      #   The subset map representing the extensions to perform.
      # @param extendee [CommaSequence] The selector being extended.
      # @param extend_node [Sass::Tree::ExtendNode]
      #   The node that caused this extension.
      # @param parent_directives [Array<Sass::Tree::DirectiveNode>]
      #   The parent directives containing `extend_node`.
      # @param allow_compound_target [Boolean]
      #   Whether `extendee` is allowed to contain compound selectors.
      # @raise [Sass::SyntaxError] if this extension is invalid.
      def populate_extends(extends, extendee, extend_node = nil, parent_directives = [],
          allow_compound_target = false)
        extendee.members.each do |seq|
          if seq.members.size > 1
            raise Sass::SyntaxError.new("Can't extend #{seq}: can't extend nested selectors")
          end

          sseq = seq.members.first
          if !sseq.is_a?(Sass::Selector::SimpleSequence)
            raise Sass::SyntaxError.new("Can't extend #{seq}: invalid selector")
          elsif sseq.members.any? {|ss| ss.is_a?(Sass::Selector::Parent)}
            raise Sass::SyntaxError.new("Can't extend #{seq}: can't extend parent selectors")
          end

          sel = sseq.members
          if !allow_compound_target && sel.length > 1
            @@compound_extend_deprecation.warn(sseq.filename, sseq.line, <<WARNING)
Extending a compound selector, #{sseq}, is deprecated and will not be supported in a future release.
See https://github.com/sass/sass/issues/1599 for details.
WARNING
          end

          members.each do |member|
            unless member.members.last.is_a?(Sass::Selector::SimpleSequence)
              raise Sass::SyntaxError.new("#{member} can't extend: invalid selector")
            end

            extends[sel] = Sass::Tree::Visitors::Cssize::Extend.new(
              member, sel, extend_node, parent_directives, false)
          end
        end
      end

      # Unifies this with another comma selector to produce a selector
      # that matches (a subset of) the intersection of the two inputs.
      #
      # @param other [CommaSequence]
      # @return [CommaSequence, nil] The unified selector, or nil if unification failed.
      # @raise [Sass::SyntaxError] If this selector cannot be unified.
      #   This will only ever occur when a dynamic selector,
      #   such as {Parent} or {Interpolation}, is used in unification.
      #   Since these selectors should be resolved
      #   by the time extension and unification happen,
      #   this exception will only ever be raised as a result of programmer error
      def unify(other)
        results = members.map {|seq1| other.members.map {|seq2| seq1.unify(seq2)}}.flatten.compact
        results.empty? ? nil : CommaSequence.new(results.map {|cseq| cseq.members}.flatten)
      end

      # Returns a SassScript representation of this selector.
      #
      # @return [Sass::Script::Value::List]
      def to_sass_script
        Sass::Script::Value::List.new(members.map do |seq|
          Sass::Script::Value::List.new(seq.members.map do |component|
            next if component == "\n"
            Sass::Script::Value::String.new(component.to_s)
          end.compact, separator: :space)
        end, separator: :comma)
      end

      # Returns a string representation of the sequence.
      # This is basically the selector string.
      #
      # @return [String]
      def inspect
        members.map {|m| m.inspect}.join(", ")
      end

      # @see AbstractSequence#to_s
      def to_s(opts = {})
        @members.map do |m|
          next if opts[:placeholder] == false && m.invisible?
          m.to_s(opts)
        end.compact.
          join(opts[:style] == :compressed ? "," : ", ").
          gsub(", \n", ",\n")
      end

      private

      def _hash
        members.hash
      end

      def _eql?(other)
        other.class == self.class && other.members.eql?(members)
      end
    end
  end
end
