# frozen_string_literal: true

require_relative "../base"

module Neetob
  class CLI
    module Users
      class Audit < Base
        attr_accessor :sandbox

        def initialize(sandbox = false)
          super()
          @sandbox = sandbox
        end

        def run
          users_data = users_for_all_available_apps
          users = extract_values_from_user_data(users_data)
          email_repos_map = create_email_repos_map(users)
          unique_users = users.uniq { |user| [user[0], user[1]] }.sort
          ui.info("\nUsers with multiple emails:")
          find_users_with_multiple_emails(unique_users.transpose, email_repos_map)
          ui.info("Users with emails having 3rd party domains:")
          find_users_with_invalid_emails(unique_users.transpose, email_repos_map)
        end

        private

          def users_for_all_available_apps
            find_all_matching_apps(["*"], :github, sandbox, true).map do |app|
              clone_repo_and_get_users(app).split("\n").map { |user| "#{user} #{app}" }
            end
          end

          def extract_values_from_user_data(users)
            users.flatten.map do |user|
              values = user.strip.split(" ")[1..-1]
              [values[0..-3].join(" "), clean_email(values[-2]), clean_repo_name(values[-1])]
            end
          end

          def clone_repo_and_get_users(app)
            app_name_without_org_suffix = app.split("/")[1]
            `git -C ./#{app_name_without_org_suffix} shortlog -sne`
          end

          def create_email_repos_map(users)
            map = {}
            users.each do |user|
              email = user[1]
              repo = user[2]
              map[email] = [] unless map.key?(email)
              map[email].push(repo)
            end
            map
          end

          def find_users_with_multiple_emails(users, email_repos_map)
            user_emails = {}
            users[0].each_with_index do |name, index|
              email = users[1][index]
              user_emails[name] = [] unless user_emails.key?(name)
              user_emails[name].push(email)
            end
            user_with_multiple_emails = user_emails.filter { |_, val| val.length > 1 }
            table_rows = create_rows_and_add_repos(user_with_multiple_emails, email_repos_map)
            create_and_show_table(table_rows, table_columns)
          end

          def find_users_with_invalid_emails(users, email_repos_map)
            user_with_invalid_emails = {}
            users[1].each_with_index do |email, index|
              name = users[0][index]
              if invalid_email?(email)
                user_with_invalid_emails[name] = [] unless user_with_invalid_emails.key?(name)
                user_with_invalid_emails[name].push(email)
              end
            end
            table_rows = create_rows_and_add_repos(user_with_invalid_emails, email_repos_map)
            create_and_show_table(table_rows, table_columns)
          end

          def table_columns
            [:Name, :Email, :Repo]
          end

          def create_rows_and_add_repos(users, email_repos_map)
            users.map do |name, emails|
              repos = emails.map { |email| email_repos_map[email] }
              [name, emails.join(", "), join_and_truncate_repos(repos)]
            end
          end

          def create_and_show_table(data, column_names)
            table = Terminal::Table.new headings: column_names, rows: data
            ui.error(table)
          end

          def join_and_truncate_repos(repos)
            repos.flatten.uniq.join(",").truncate(35)
          end

          def clean_email(email)
            email.gsub(/<|>/, "")
          end

          def clean_repo_name(repo)
            repo.gsub("bigbinary/", "")
          end

          def invalid_email?(email)
            !allowed_email_domains.any? { |domain| email.downcase.include?(domain) }
          end

          def allowed_email_domains
            ["github", "gmail", "bigbinary"]
          end
      end
    end
  end
end