# frozen_string_literal: true

module Reports
  class DocxRenderer
    def self.render_p_element(docx, element, options = {})
      docx.p do
        element[:children].each do |text_el|
          if text_el[:type] == 'text'
            style = text_el[:style] || {}
            text text_el[:value], style
            text ' ' if text_el[:value] != ''
          elsif text_el[:type] == 'br' && !options[:skip_br]
            br
          elsif text_el[:type] == 'a'
            Reports::DocxRenderer.render_link_element(self, text_el, options)
          end
        end
      end
    end

    def self.render_link_element(node, link_item, options = {})
      scinote_url = options[:scinote_url]
      link_style = options[:link_style]

      if link_item[:link]
        link_url = Reports::Utils.link_prepare(scinote_url, link_item[:link])
        node.link link_item[:value], link_url, link_style
      else
        node.text link_item[:value], link_style
      end
      node.text ' ' if link_item[:value] != ''
    end

    def self.render_img_element(docx, element, options = {})
      style = element[:style]

      if options[:table]
        max_width = (style[:max_width] / options[:table][:columns].to_f)
        if style[:width] > max_width
          style[:height] = (max_width / style[:width].to_f) * style[:height]
          style[:width] = max_width
        end
      end

      docx.img element[:data] do
        data element[:blob].download
        width style[:width]
        height style[:height]
        align style[:align] || :left
      end
    end

    def self.render_list_element(docx, element, options = {})
      bookmark_items = Reports::DocxRenderer.recursive_list_items_renderer(docx, element)

      bookmark_items.each_with_index do |(key, item), index|
        if item[:type] == 'image'
          docx.bookmark_start id: index, name: key
          docx.p do
            br
            text item[:blob]&.filename.to_s
          end
          Reports::DocxRenderer.render_img_element(docx, item)
          docx.bookmark_end id: index
        elsif item[:type] == 'table'
          docx.bookmark_start id: index, name: key

          # Bookmark won't work with table only, empty p element added
          docx.p do
            br
            text ''
          end
          Reports::DocxRenderer.render_table_element(docx, item, options)
          docx.bookmark_end id: index
        end
      end
    end

    # rubocop:disable Metrics/BlockLength
    def self.recursive_list_items_renderer(node, element, bookmark_items: {})
      node.public_send(element[:type]) do
        element[:data].each do |values_array|
          li do
            values_array.each do |item|
              case item
              when Hash
                if %w(ul ol li).include?(item[:type])
                  Reports::DocxRenderer.recursive_list_items_renderer(self, item, bookmark_items: bookmark_items)
                elsif %w(a).include?(item[:type])
                  Reports::DocxRenderer.render_link_element(self, item)
                elsif %w(image).include?(item[:type])
                  bookmark_items[item[:bookmark_id]] = item
                  link I18n.t('projects.reports.renderers.lists.appended_image',
                              name: item[:blob]&.filename), item[:bookmark_id] do
                    internal true
                  end
                elsif %w(table).include?(item[:type])
                  bookmark_items[item[:bookmark_id]] = item
                  link I18n.t('projects.reports.renderers.lists.appended_table'), item[:bookmark_id] do
                    internal true
                  end
                elsif %w(text).include?(item[:type])
                  # TODO: Text with styles, not working yet.
                  style = item[:style] || {}
                  text item[:value], style
                end
              else
                text item
              end
            end
          end
        end
      end
      bookmark_items
    end
    # rubocop:enable Metrics/BlockLength

    def self.render_table_element(docx, element, options = {})
      docx_table = []
      element[:data].each do |row|
        docx_row = []
        row[:data].each do |cell|
          docx_cell = Caracal::Core::Models::TableCellModel.new do |c|
            cell.each do |content|
              if content[:type] == 'p'
                Reports::DocxRenderer.render_p_element(c, content, options.merge({ skip_br: true }))
              elsif content[:type] == 'table'
                Reports::DocxRenderer.render_table_element(c, content, options)
              elsif content[:type] == 'image'
                Reports::DocxRenderer.render_img_element(c, content, table: { columns: row.children.length / 3 })
              end
            end
          end
          docx_row.push(docx_cell)
        end
        docx_table.push(docx_row)
      end
      docx.table docx_table, border_size: Constants::REPORT_DOCX_TABLE_BORDER_SIZE
    end

    def self.render_asset_image(docx, asset)
      return unless asset

      asset_preview = Reports::Utils.image_prepare(asset)

      dimension = FastImage.size(asset_preview.processed.service_url)
      return unless dimension

      x = dimension[0]
      y = dimension[1]
      if x > 300
        y = y * 300 / x
        x = 300
      end
      blob_data = if asset_preview.class == ActiveStorage::Preview
                    asset_preview.image.download
                  else
                    asset_preview.blob.download
                  end

      docx.img asset_preview.service_url.split('&')[0] do
        data blob_data
        width x
        height y
      end
    end
  end
end
