module Attachable
  extend ActiveSupport::Concern

  included do
    has_one_attached :attachment
    attr_accessor :cached_attachment

    validates :attachment,
              presence: true,
              file_content_type: {
                allow: ->(record) { record.accepted_content_types },
                if: -> { association_class && attachment.attached? && attachment.new_record? },
                message: ->(record, *) do
                  I18n.t("#{record.model_name.plural}.errors.messages.wrong_content_type",
                         content_type: record.attachment_content_type,
                         accepted_content_types: record.class.humanized_accepted_content_types)
                end
              },
              file_size: {
                less_than_or_equal_to: ->(record) { record.max_file_size.megabytes },
                if: -> { association_class && attachment.attached? && attachment.new_record? },
                message: ->(record, *) do
                  I18n.t("#{record.model_name.plural}.errors.messages.in_between",
                         min: "0 Bytes",
                         max: "#{record.max_file_size} MB")
                end
              }

    before_validation :set_attachment_from_cached_attachment, if: -> { cached_attachment.present? }
  end

  def association_class
    type = send("#{association_name}_type")

    type.constantize if type.present?
  end

  def set_cached_attachment_from_attachment
    self.cached_attachment = attachment.signed_id
  end

  def set_attachment_from_cached_attachment
    self.attachment = cached_attachment
  end

  def attachment_file_name
    attachment.filename.to_s if attachment.attached?
  end

  def attachment_content_type
    attachment.blob.content_type if attachment.attached?
  end

  def attachment_file_size
    if attachment.attached?
      attachment.blob.byte_size
    else
      0
    end
  end

  def file_path
    ActiveStorage::Blob.service.path_for(attachment.blob.key)
  end
end
