# frozen_string_literal: true

require 'tty/table'
require 'chronicle/utils/hash_utils'
require 'active_support/core_ext/string/filters'
require 'active_support/core_ext/hash/reverse_merge'

module Chronicle
  module ETL
    class TableLoader < Chronicle::ETL::Loader

      register_connector do |r|
        r.identifier = :table
        r.description = 'an ASCII table'
      end

      setting :truncate_values_at, default: 40
      setting :table_renderer, default: :basic
      setting :fields_exclude, default: ['type']
      setting :header_row, default: true

      def load(record)
        records << record
      end

      def finish
        return if records.empty?

        headers = gather_headers(records)
        rows = build_rows(records, headers)

        render_table(headers, rows)
      end

      def records
        @records ||= []
      end

      private

      def render_table(headers, rows)
        @table = TTY::Table.new(header: (headers if @config.header_row), rows: rows)
        puts @table.render(
          @config.table_renderer.to_sym,
          padding: [0, 2, 0, 0]
        )
      rescue TTY::Table::ResizeError
        # The library throws this error before trying to render the table
        # vertically. These options seem to work.
        puts @table.render(
          @config.table_renderer.to_sym,
          padding: [0, 2, 0, 0],
          width: 10_000,
          resize: false
        )
      end

      def gather_headers(records)
        records_flattened = records.map do |record|
          Chronicle::Utils::HashUtils.flatten_hash(record.to_h)
        end
        records_flattened.flat_map(&:keys).uniq
      end

      def build_rows(records, headers)
        records.map do |record|
          values = Chronicle::Utils::HashUtils.flatten_hash(record.to_h)
            .values_at(*headers)
            .map { |value| force_utf8(value.to_s) }

          values = values.map { |value| value.truncate(@config.truncate_values_at) } if @config.truncate_values_at

          values
        end
      end
    end
  end
end
