class TailwindFormBuilder < ActionView::Helpers::FormBuilder
  class_attribute :text_field_helpers, default: field_helpers - [:label, :check_box, :radio_button, :fields_for, :fields, :hidden_field, :file_field]
  #  leans on the FormBuilder class_attribute `field_helpers`
  #  you'll want to add a method for each of the specific helpers listed here if you want to style them

  TEXT_FIELD_STYLE = "flex bg-gray-200 rounded py-2 px-4 text-bluetang font-semibold leading-tight focus:outline-none focus:bg-white border border-platinum".freeze
  SELECT_FIELD_STYLE = "block bg-gray-200 text-bluetang py-2 px-4 font-semibold rounded leading-tight focus:outline-none focus:bg-white border border-platinum".freeze
  SUBMIT_BUTTON_STYLE = "cursor-pointer font-bold text-lg text-platinum hover:text-bronze bg-cobalt-vivid hover:bg-deepcove border-2 border-cobalt-vivid py-2 px-4 rounded".freeze

  text_field_helpers.each do |field_method|
    class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
        def #{field_method}(method, options = {})
          if options.delete(:tailwindified)
            super
          else
            text_like_field(#{field_method.inspect}, method, options)
          end
        end
    RUBY_EVAL
  end

  def submit(value = nil, options = {})
    custom_opts, opts = partition_custom_opts(options)
    classes = apply_style_classes(SUBMIT_BUTTON_STYLE, custom_opts)

    super(value, {class: classes}.merge(opts))
  end

  def select(method, choices = nil, options = {}, html_options = {}, &block)
    custom_opts, opts = partition_custom_opts(options)
    classes = apply_style_classes(SELECT_FIELD_STYLE, custom_opts, method)

    labels = labels(method, custom_opts[:label], options)
    field = super(method, choices, opts, html_options.merge({class: classes}), &block)

    labels + field
  end

  def file_field(method, options = {})
    options[:class] = Array(options[:class]) << "block w-full px-1 py-[1px] text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 dark:text-gray-400 focus:outline-none dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100"
    # You can add more classes as needed for padding, margin, etc., e.g., p-2.5
    super(method, options)
  end

  private

  def text_like_field(field_method, object_method, options = {})
    custom_opts, opts = partition_custom_opts(options)

    classes = apply_style_classes(TEXT_FIELD_STYLE, custom_opts, object_method)
    puts "classes: #{classes}"

    field = send(field_method, object_method, {
      class: classes,
      title: errors_for(object_method)&.join(" ")
    }.compact.merge(opts).merge({tailwindified: true}))

    labels = labels(object_method, custom_opts[:label], options)

    labels + field
  end

  def labels(object_method, label_options, field_options)
    label = tailwind_label(object_method, label_options, field_options)
    error_label = error_label(object_method, field_options)

    @template.content_tag("div", label + error_label, {class: "flex justify-between"})
  end

  def tailwind_label(object_method, label_options, field_options)
    text, label_opts = if label_options.present?
      [label_options[:text], label_options.except(:text)]
    else
      [object_method.to_s.titleize, {}]
    end

    label_classes = label_opts[:class] || "block shrink-0 text-platinum font-bold md:text-right mb-1 md:mb-0 pr-4"
    label_classes += " dark:text-brightlava" if field_options[:disabled]
    label(object_method, text, {
      class: label_classes
    }.merge(label_opts.except(:class)))
  end

  def error_label(object_method, options)
    if errors_for(object_method).present?
      error_message = @object.errors[object_method].collect(&:titleize).join(", ")
      tailwind_label(object_method, {text: error_message, class: " font-bold text-right text-bronze"}, options)
    end
  end

  def border_color_classes(object_method)
    if errors_for(object_method).present?
      " border-4 dark:border-bronze focus:border-atmosphere"
    else
      ""
      # " border border-platinum focus:border-yellow-700"
    end
  end

  def apply_style_classes(classes, custom_opts, object_method = nil)
    classes + border_color_classes(object_method) + " #{custom_opts[:class]}"
  end

  CUSTOM_OPTS = [:label, :class].freeze
  def partition_custom_opts(opts)
    opts.partition { |k, v| CUSTOM_OPTS.include?(k) }.map(&:to_h)
  end

  def errors_for(object_method)
    return unless @object.present? && object_method.present?

    @object.errors[object_method]
  end
end