# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0

# frozen_string_literal: true

# Shows how to get a list of work items from a storage object, render it in both
# HTML and text formats, and use Amazon Simple Email Service (Amazon SES) to send it as
# an email report.
#
# When the list of items is longer than a specified threshold, it is included as a CSV
# attachment to the email instead of in the body of the email itself.

require 'logger'
require 'erb'
require 'json'
require 'csv'
require 'mail'
require 'mime'
require_relative 'aurora'

# Encapsulates a report resource that gets work items from an
# Amazon Aurora database and uses Amazon SES to send emails about them.
class Report
  # @param db_wrapper: An object that manages moving data in and out of the underlying database.
  # @param email_sender: The email address from which the email report is sent.
  # @param ses_client: An Amazon SES client.
  def initialize(db_wrapper, email_sender, ses_client)
    @logger = Logger.new($stdout)
    @db_wrapper = db_wrapper
    @email_sender = email_sender
    @ses_client = ses_client
    @timestamp = Time.now.strftime('%H:%M on %h %d %Y')
  end

  # Formats the report as a ready-to-send email message, including attachment
  def format_mime_message(email_recipient, text, html, attachment)
    @logger.info('Beginning to format message...')

    mail = Mail.new
    mail.sender = @email_sender
    mail.to = email_recipient
    mail.subject = 'Work Items Report'
    mail.content_type = 'multipart/mixed'

    html_part = Mail::Part.new do
      content_type  'text/html; charset=UTF-8'
      body          html
    end

    text_part = Mail::Part.new do
      body          text
    end

    mail.part content_type: 'multipart/alternative' do |p|
      p.html_part = html_part
      p.text_part = text_part
    end

    mail.attachments[attachment] = File.read(attachment)

    mail.content_type = mail.content_type.gsub('alternative', 'mixed')
    mail.charset = 'UTF-8'
    mail.content_transfer_encoding = 'quoted-printable'
    @logger.info(mail)
    mail
  end

  # Renders work items to CSV format, with the field names as a header row.
  #
  # @param work_items: The work items to include in the CSV output.
  # @return: Work items rendered to a string in CSV format.
  def render_csv(work_items, file_name)
    CSV.open(file_name, 'w', headers: work_items.first.keys) do |csv|
      work_items.each do |h|
        csv << h.values
      end
    end
  end

  # @return html_part
  def render_template(template_file, work_items)
    erb = ERB.new(File.read(template_file), trim_mode: '%<>')
    @work_items = work_items
    @timestamp = Time.now.strftime('%H:%M on %h %d %Y')
    erb.result(binding)
  end

  # Gets a list of work items from the database and sends an email.
  # Two versions of the email are included:
  #    1. An HTML version that formats the report as an HTML table by using Ruby's native
  #       template rendering feature. Email clients that can render HTML receive this
  #       version.
  #    2. A text version that includes the report as a list of Ruby hashes. Email
  #       clients that cannot render HTML receive this version.
  # When your Amazon SES account is in the sandbox, both the sender and recipient
  # email addresses must be registered with Amazon SES.
  # @param recipient_email [String]
  # @return [Integer] An HTTP result code.
  def post_report(recipient_email)
    @logger.info('Getting work items for report.')
    work_items = @db_wrapper.get_work_items
    @logger.debug("Prepared the following items for a report:\n#{work_items}")

    file_name = File.join(File.dirname(__FILE__), 'templates', 'report.html.erb')
    html_report = render_template(file_name, work_items)
    @logger.debug("HTML report: \n#{html_report}")

    text_report = ''
    work_items.each do |work_item|
      text_report += "\n#{work_item.to_json}"
    end
    @logger.debug("Text report: \n#{text_report}")

    @logger.info('Successfully rendered work_items into HTML & text.')

    csv_file = 'data.csv'
    render_csv(work_items, csv_file)
    @logger.info("Successfully saved work items as CSV attachment: #{csv_file}")

    @logger.info("Sending report of #{work_items.count} items to #{recipient_email}")
    if work_items.count > 5
      mime_msg = format_mime_message(recipient_email, text_report, html_report, csv_file)
      @ses_client.send_raw_email({
                                   source: @email_sender,
                                   destinations: [recipient_email],
                                   raw_message: {
                                     data: mime_msg.to_s
                                   }
                                 })
    else
      @ses_client.send_email({
                               source: @email_sender,
                               destination: {
                                 to_addresses: [recipient_email]
                               },
                               message: {
                                 subject: {
                                   data: 'Work Items Report'
                                 },
                                 body: {
                                   text: {
                                     data: text_report
                                   },
                                   html: {
                                     data: html_report
                                   }
                                 }
                               }
                             })
    end
    204
  rescue StandardError => e
    @logger.error("Couldn't send email: #{e}")
    500
  end
end
