# frozen_string_literal: true

module TinyMceImages
  extend ActiveSupport::Concern

  included do
    has_many :tiny_mce_assets,
             as: :object,
             class_name: :TinyMceAsset,
             dependent: :destroy

    before_save :clean_tiny_mce_image_urls

    def prepare_for_report(field, base64_encoded_imgs = false)
      description = self[field]

      # Check tinymce for old format
      description = TinyMceAsset.update_old_tinymce(description, self)

      tiny_mce_assets.each do |tm_asset|
        next unless tm_asset&.image&.attached?

        begin
          new_tm_asset_src =
            if base64_encoded_imgs
              tm_asset.convert_variant_to_base64(tm_asset.preview)
            else
              tm_asset.preview.processed.service_url(expires_in: Constants::URL_LONG_EXPIRE_TIME)
            end
        rescue ActiveStorage::FileNotFoundError
          next
        end
        html_description = Nokogiri::HTML(description)
        tm_asset_to_update = html_description.css(
          "img[data-mce-token=\"#{Base62.encode(tm_asset.id)}\"]"
        )[0]
        next unless tm_asset_to_update

        tm_asset_to_update.attributes['src'].value = new_tm_asset_src
        description = html_description.css('body').inner_html.to_s
      end
      description
    end

    def tinymce_render(field)
      TinyMceAsset.generate_url(self[field], self)
    end

    # Takes array of old/new TinyMCE asset ID pairs
    # and updates references in assosiated object's description
    def reassign_tiny_mce_image_references(images = [])
      object_field = Extends::RICH_TEXT_FIELD_MAPPINGS[self.class.name]
      description = read_attribute(object_field)

      # Check tinymce for old format
      description = TinyMceAsset.update_old_tinymce(description, self)

      parsed_description = Nokogiri::HTML(description)
      images.each do |image|
        old_id = image[0]
        new_id = image[1]
        image = parsed_description.at_css("img[data-mce-token=\"#{Base62.encode(old_id)}\"]")

        unless image
          Rails.logger.error "TinyMCE Asset with id #{old_id} not in text"
          next
        end

        image['data-mce-token'] = Base62.encode(new_id)
      end
      update(object_field => parsed_description.css('body').inner_html.to_s)
    end

    def clone_tinymce_assets(target, team)
      cloned_img_ids = []
      tiny_mce_assets.each do |tiny_img|
        next unless tiny_img.image.attached? && tiny_img.image.service.exist?(tiny_img.image.blob.key)

        tiny_img_clone = TinyMceAsset.create(
          estimated_size: tiny_img.estimated_size,
          object: target,
          team: team
        )

        tiny_img.duplicate_file(tiny_img_clone)
        target.tiny_mce_assets << tiny_img_clone
        cloned_img_ids << [tiny_img.id, tiny_img_clone.id]
      end
      target.reassign_tiny_mce_image_references(cloned_img_ids)
    end

    def copy_unknown_tiny_mce_images
      asset_team_id = Team.search_by_object(self).id
      return unless asset_team_id

      object_field = Extends::RICH_TEXT_FIELD_MAPPINGS[self.class.name]

      image_changed = false
      parsed_description = Nokogiri::HTML(read_attribute(object_field))
      parsed_description.css('img').each do |image|
        if image['data-mce-token']
          asset = TinyMceAsset.find_by_id(Base62.decode(image['data-mce-token']))

          next if asset && (asset.object == self || asset_team_id != asset.team_id)

        else
          url = image['src']
          image_type = FastImage.type(url).to_s
          next unless image_type

          begin
            new_image = Down.download(url, max_size: Rails.configuration.x.file_max_size_mb.megabytes)
          rescue Down::TooLarge => e
            Rails.logger.error e.message
            next
          end

          new_image_filename = Asset.generate_unique_secure_token + '.' + image_type
        end

        new_asset = TinyMceAsset.create(
          object: self,
          team_id: asset_team_id
        )

        new_asset.transaction do
          new_asset.save!
          if image['data-mce-token']
            asset.duplicate_file(new_asset)
          else
            new_asset.image.attach(io: new_image, filename: new_image_filename)
          end
        end

        image['src'] = ''
        image['class'] = 'img-responsive'
        image['data-mce-token'] = Base62.encode(new_asset.id)
        image_changed = true
      end
      update(object_field => parsed_description.css('body').inner_html.to_s) if image_changed
    rescue StandardError => e
      Rails.logger.error "Object: #{self.class.name}, id: #{id}, error: #{e.message}"
    end

    private

    def clean_tiny_mce_image_urls
      object_field = Extends::RICH_TEXT_FIELD_MAPPINGS[self.class.name]
      return unless changed.include?(object_field.to_s)

      image_changed = false
      parsed_description = Nokogiri::HTML(read_attribute(object_field))
      parsed_description.css('img[data-mce-token]').each do |image|
        image['src'] = ''
        image['class'] = 'img-responsive'
        image_changed = true
      end
      self[object_field] = parsed_description.to_html if image_changed
    end
  end
end
