module CarouselHelper
  def carousel_for(images, options = {}, &block)
    Carousel.new(self, images, options, block).html
  end

  class Carousel
    def initialize(view, images, options, block)
      @view = view
      @images = images
      @options = options
      @block = block
    end

    def html
      css = ["carousel", "slide"] << options[:class].to_s.split(" ")

      content = [].tap do |content|
        content << indicators if show_indicators?
        content << slides
        content << controls if show_controls?
      end

      content_tag(:div, safe_join(content), id: uid, class: css)
    end

    private

    attr_accessor :view, :images, :options, :block
    delegate :link_to, :content_tag, :image_tag, :safe_join, :concat, :capture, to: :view

    def show_controls?
      options.fetch(:controls, true)
    end

    def show_indicators?
      options.fetch(:indicators, true)
    end

    def uid
      @uid ||= "carousel_#{SecureRandom.hex(6)}"
    end

    def indicators
      items = images.count.times.map { |index| indicator_tag(index) }
      content_tag(:ol, safe_join(items), class: 'carousel-indicators')
    end

    def indicator_tag(index)
      options = {
        class: (index.zero? ? 'active' : ''),
        data: { 
          target: "##{uid}", 
          slide_to: index
        }
      }

      content_tag(:li, '', options)
    end

    def slides
      items = images.map.with_index { |image, index| slide_tag(image, index.zero?) }
      content_tag(:div, safe_join(items), class: 'carousel-inner')
    end

    def slide_tag(image, is_active)
      options = {
        class: (is_active ? 'carousel-item active' : 'carousel-item'),
      }

      slide_content = @block.present? ? capture(image, &@block) : image_tag(image)
      content_tag(:div, slide_content, options)
    end

    def controls
      safe_join([control_tag('prev'), control_tag('next')])
    end

    def control_tag(direction)
      options = {
        class: "carousel-control-#{direction}",
        data: { slide: direction },
        role: "button"
      }

      link_to "##{uid}", options do
        concat content_tag(:span, '', class: "carousel-control-#{direction}-icon", aria: { hidden: true })
        concat content_tag(:span, direction.titleize, class: "sr-only")
      end
    end
  end
end
