# frozen_string_literal: true

require 'terminal-table'
require 'date'
require 'ascii_charts'
require_relative 'painter'
require_relative 'constants'
require_relative 'aggregators'
require_relative 'historians'

module Kovid
  class Tablelize
    extend Kovid::Constants
    extend Kovid::Aggregators
    extend Kovid::Historians

    class << self
      def country_table(data)
        Terminal::Table.new(title: country_title(data),
                            headings: CASES_DEATHS_RECOVERED_CTODAY_DTODAY,
                            rows: [country_row(data)])
      end

      def full_country_table(data)
        Terminal::Table.new(title: country_title(data),
                            headings: FULL_COUNTRY_TABLE_HEADINGS,
                            rows: [full_country_row(data)])
      end

      def full_province_table(province)
        Terminal::Table.new(
          title: province['province'].upcase,
          headings: FULL_PROVINCE_TABLE_HEADINGS,
          rows: [province_row(province)]
        )
      end

      def full_state_table(state)
        Terminal::Table.new(
          title: state['state'].upcase,
          headings: FULL_STATE_TABLE_HEADINGS,
          rows: [country_row(state)]
        )
      end

      def compare_countries_table(data)
        rows = []

        data.each do |country|
          base_rows = country_row(country)
          rows << base_rows.unshift(country_title(country))
        end

        align_columns(:compare_country_table,
                      Terminal::Table.new(
                        headings: COMPARE_COUNTRIES_TABLE_HEADINGS,
                        rows: rows
                      ))
      end

      def compare_countries_table_full(data)
        rows = data.map { |country| compare_countries_full_row(country) }

        align_columns(:compare_country_table_full,
                      Terminal::Table.new(headings: COMPARE_COUNTRY_TABLE_FULL,
                                          rows: rows))
      end

      def compare_us_states(data)
        rows = data.map.with_index do |state, index|
          if index.odd?
            us_state_row(state)
          else
            us_state_row(state).map(&:paint_highlight)
          end
        end

        align_columns(:compare_us_states,
                      Terminal::Table.new(headings: COMPARE_STATES_HEADINGS,
                                          rows: rows))
      end

      def compare_provinces(data)
        rows = data.map { |province| compare_provinces_row(province) }

        align_columns(:compare_provinces,
                      Terminal::Table.new(headings: COMPARE_PROVINCES_HEADINGS,
                                          rows: rows))
      end

      def cases(cases)
        Terminal::Table.new(
          title: '🌍 Total Number of Incidents Worldwide'.upcase,
          headings: CASES_DEATHS_RECOVERED,
          rows: [cases_row(cases)]
        )
      end

      private

      def country_title(data)
        iso = data['countryInfo']['iso2']
        if iso.nil?
          data['country'].upcase
        else
          "#{country_emoji(iso)} #{data['country'].upcase}"
        end
      end

      def country_emoji(iso)
        COUNTRY_LETTERS.values_at(*iso.chars).pack('U*') + \
          8203.chr(Encoding::UTF_8)
      end

      def cases_row(data)
        [
          Kovid.comma_delimit(data['cases']),
          Kovid.comma_delimit(data['deaths']),
          Kovid.comma_delimit(data['recovered'])
        ]
      end

      # Also works for state
      def country_row(data)
        [
          Kovid.comma_delimit(data['cases']),
          Kovid.add_plus_sign(data['todayCases']),
          Kovid.comma_delimit(data['deaths']),
          Kovid.add_plus_sign(data['todayDeaths']),
          Kovid.comma_delimit(data['recovered'])
        ]
      end

      def full_country_row(data)
        [
          Kovid.comma_delimit(data['cases']),
          Kovid.comma_delimit(data['deaths']),
          Kovid.comma_delimit(data['recovered']),
          Kovid.add_plus_sign(data['todayCases']),
          Kovid.add_plus_sign(data['todayDeaths']),
          Kovid.comma_delimit(data['critical']),
          Kovid.comma_delimit(data['casesPerOneMillion'])
        ]
      end

      def province_row(data)
        [
          data['stats']['confirmed'],
          data['stats']['deaths'],
          data['stats']['recovered']
        ]
      end

      def compare_provinces_row(data)
        [
          data['province'].upcase,
          province_row(data)
        ].flatten
      end

      def compare_countries_full_row(data)
        [
          data.fetch('country'),
          full_country_row(data)
        ].flatten
      end

      def us_state_row(data)
        [
          data.fetch('state').upcase,
          Kovid.comma_delimit(data.fetch('cases')),
          Kovid.add_plus_sign(data['todayCases']),
          Kovid.comma_delimit(data['deaths']),
          Kovid.add_plus_sign(data['todayDeaths']),
          Kovid.comma_delimit(data.fetch('active'))
        ]
      end

      def aggregated_row(data)
        [
          Kovid.comma_delimit(data['cases']),
          Kovid.add_plus_sign(data['todayCases']),
          Kovid.comma_delimit(data['deaths']),
          Kovid.add_plus_sign(data['todayDeaths']),
          Kovid.comma_delimit(data['recovered']),
          Kovid.comma_delimit(data['active']),
          Kovid.comma_delimit(data['critical'])
        ]
      end

      def scale(msg)
        rows = [[msg]]
        puts Terminal::Table.new title: 'SCALE', rows: rows
      end

      def aggregated_table(collated_data, continent, iso, emoji)
        title = aggregated_table_title(continent, iso, emoji)

        Terminal::Table.new(
          title: title,
          headings: CONTINENTAL_AGGREGATE_HEADINGS,
          rows: [aggregated_row(collated_data)]
        )
      end

      def aggregated_table_title(continent, iso, emoji)
        aggregated_data_continent = ' Aggregated Data on ' \
          "#{continent} (#{iso.size} States)".upcase

        if emoji.codepoints.size > 1
          emoji + 8203.chr(Encoding::UTF_8) + aggregated_data_continent
        else
          emoji + aggregated_data_continent
        end
      end

      def align_columns(table_type, table)
        return table unless RIGHT_ALIGN_COLUMNS[table_type]

        RIGHT_ALIGN_COLUMNS[table_type].each do |col_no|
          table.align_column(col_no, :right)
        end
        table
      end
    end
  end
end