# frozen_string_literal: true

module Thinreports
  module SectionReport
    module Renderer
      module SectionHeight
        LayoutInfo = Struct.new(:shape, :content_height, :top_margin, :bottom_margin)

        def section_height(section)
          return [section.min_height || 0, section.schema.height].max if !section.schema.auto_stretch? || section.items.empty?

          item_layouts = section.items.map { |item| item_layout(section, item.internal) }.compact

          min_bottom_margin = item_layouts.each_with_object([]) do |l, margins|
            margins << l.bottom_margin if l.shape.format.affect_bottom_margin?
          end.min.to_f

          max_content_bottom = item_layouts.each_with_object([]) do |l, bottoms|
            bottoms << l.top_margin + l.content_height if l.shape.format.affect_bottom_margin?
          end.max.to_f

          [section.min_height || 0, max_content_bottom + min_bottom_margin].max
        end

        def calc_float_content_bottom(section)
          item_layouts = section.items.map { |item| item_layout(section, item.internal) }.compact
          item_layouts
            .map { |l| l.top_margin + l.content_height }
            .max.to_f
        end

        def item_layout(section, shape)
          if shape.type_of?(Core::Shape::TextBlock::TYPE_NAME)
            text_layout(section, shape)
          elsif shape.type_of?(Core::Shape::StackView::TYPE_NAME)
            stack_view_layout(section, shape)
          elsif shape.type_of?(Core::Shape::ImageBlock::TYPE_NAME)
            image_block_layout(section, shape)
          elsif shape.type_of?('ellipse')
            cy, ry = shape.format.attributes.values_at('cy', 'ry')
            static_layout(section, shape, cy - ry, ry * 2)
          elsif shape.type_of?('line')
            y1, y2 = shape.format.attributes.values_at('y1', 'y2')
            static_layout(section, shape, [y1, y2].min, (y2 - y1).abs)
          else
            y, height = shape.format.attributes.values_at('y', 'height')
            raise ArgumentError.new("Unknown layout for #{shape}") if height == nil || y == nil
            static_layout(section, shape, y, height)
          end
        end

        def static_layout(section, shape, y, height)
          LayoutInfo.new(shape, height, y, section.schema.height - height - y)
        end

        def image_block_layout(section, shape)
          y, height = shape.format.attributes.values_at('y', 'height')
          if shape.style.finalized_styles['position-y'] == 'top'
            dimensions = pdf.shape_iblock_dimenions(shape)
            content_height = dimensions ? dimensions[1] : 0

            LayoutInfo.new(shape, content_height, y, section.schema.height - height - y)
          else
            static_layout(section, shape, y, height)
          end
        end

        def calc_text_block_height(shape)
          height = 0

          pdf.draw_shape_tblock(shape) do |array, options|
            modified_options = options.merge(at: [0, 10_000], height: 10_000)
            height = pdf.pdf.height_of_formatted(array, modified_options)
          end
          height
        end

        def text_layout(section, shape)
          y, schema_height = shape.format.attributes.values_at('y', 'height')

          content_height = if shape.style.finalized_styles['overflow'] == 'expand'
            [schema_height, calc_text_block_height(shape)].max
          else
            schema_height
          end

          LayoutInfo.new(shape, content_height, y, section.schema.height - schema_height - y)
        end

        def stack_view_layout(section, shape)
          schema_height = 0
          shape.format.rows.each {|row| schema_height += row.attributes['height']}

          y = shape.format.attributes['y']
          LayoutInfo.new(shape, stack_view_renderer.section_height(shape), y, section.schema.height - schema_height - y)
        end
      end
    end
  end
end