# frozen_string_literal: true

require_relative 'color_string'
require 'readline'

module MakeMenu
  # A panel above the menu displaying the status of Docker containers.
  # The mapping of TextLabel => ContainerName must be defined in a constant called CONTAINERS
  class StatusPanel
    String.include(ColorString)

    # Print panel
    def display
      return if containers.empty?

      puts "\n#{panel}"
    end

    protected

    # Return a hash mapping label to container name
    # This is assumed to be provided as a constant called CONTAINERS
    # @return [Hash{String=>String}]
    def containers
      Object.const_get "#{self.class.name}::CONTAINERS"
    rescue NameError
      {}
    end

    # Override this to change the colors for running / not running
    def colors_if_running
      {
        true => %i[green_bg bold white],
        false => %i[red_bg bold dark]
      }.freeze
    end

    # Override this to limit each row to a maximum number of labels
    def max_labels_per_line
      containers.size
    end

    private

    # @return [String] Text representation of the panel
    # rubocop:disable Metrics/MethodLength
    def panel
      return @panel if @panel

      @panel = ''
      labels_on_this_line = 0
      line_buffer = ''

      containers.each do |label, container|
        if (labels_on_this_line + 1) > labels_per_line
          @panel += "#{left_indent(labels_on_this_line)}#{line_buffer}\n\n"
          labels_on_this_line = 0
          line_buffer = ''
        end

        text = label.align(:center, width: max_label_width, pad_right: true)
                    .color(colors_if_running[running?(container)])

        line_buffer += " #{text} "

        labels_on_this_line += 1
      end

      @panel += "#{left_indent(labels_on_this_line)}#{line_buffer}\n\n"
    end
    # rubocop:enable Metrics/MethodLength

    # @return [String] List of Docker containers and information
    def docker_ps
      @docker_ps ||= `docker compose ps`
    end

    # @return [Boolean] whether specified container is running
    def running?(container)
      docker_ps.include? container
    end

    # Return the left indent for this line of labels
    # @param [Integer] number_of_labels Number of labels on this line
    # @return [String]
    def left_indent(number_of_labels)
      spaces = (::TTY::Screen.cols - (number_of_labels * (max_label_width + 2))) / 2
      spaces = [spaces, 0].max
      ' ' * spaces
    end

    # @return [Integer] Maximum label width, with padding
    def max_label_width
      @max_label_width ||= containers.map do |label, _container|
        label.length
      end.max + 2
    end

    # @return [Integer] Number of labels that can fit on one line
    def labels_per_line
      @labels_per_line ||= [
        (::TTY::Screen.cols / max_label_width) - 1,
        max_labels_per_line
      ].min
    end
  end
end