class WcoEmail::MessageStub

#
# 2024-01-05 LFG
# 2023-12-28 vp Continue.
# Only object_key, no validations.
#

def self.mbox2stubs mbox_path, tagname:, skip:

def self.mbox2stubs mbox_path, tagname:, skip:
  skip ||= 0
  self.new.mbox2stubs mbox_path, tagname: tagname, skip: skip
end

def do_process

def do_process
  @client ||= Aws::S3::Client.new(::SES_S3_CREDENTIALS)
  stub = self
  raw      = @client.get_object( bucket: stub.bucket, key: stub.object_key ).body.read
  raw      = raw.encode('utf-8', invalid: :replace, undef: :replace, replace: '_' )
  the_mail = Mail.new( raw )
  puts! the_mail, 'the_mail'
  message_id         = the_mail.header['message-id']&.decoded
  message_id       ||= "#{the_mail.date&.iso8601}::#{the_mail.from}"
  # puts! message_id, 'message_id'
  in_reply_to_id     = the_mail.header['in-reply-to']&.to_s
  # puts! in_reply_to_id, 'in_reply_to_id'
  the_mail.to        = [ 'NO-RECIPIENT' ] if !the_mail.to
  subject            = WcoEmail::Message.strip_emoji( the_mail.subject || '(wco-no-subject)' )
  # puts! subject, 'subject'
  ## Conversation
  if in_reply_to_id
    in_reply_to_msg = WcoEmail::Message.where({ message_id: in_reply_to_id }).first
    if !in_reply_to_msg
      conv = WcoEmail::Conversation.find_or_create_by({
        subject: subject,
      })
      in_reply_to_msg = WcoEmail::Message.find_or_create_by({
        message_id: in_reply_to_id,
        conversation: conv,
      })
    end
    conv = in_reply_to_msg.conversation
  else
    conv = WcoEmail::Conversation.unscoped.find_or_create_by({
      subject: subject,
    })
    conv.deleted_at = nil
  end
  ## Leadset, Lead
  from      = the_mail.from ? the_mail.from[0] : "nobody@unknown-doma.in"
  lead      = Wco::Lead.find_or_create_by_email( from )
  conv.leads.push lead
  leadset   = Wco::Leadset.from_email from
  conv.leadsets.push leadset
  # conv.save
  message   = WcoEmail::Message.unscoped.where( message_id: message_id ).first
  if message
    message.message_id = "#{Time.now.strftime('%Y%m%d')}-trash-#{message.message_id}"
    message.object_key = "#{Time.now.strftime('%Y%m%d')}-trash-#{message.object_key}"
    message.save( validate: false )
    message.delete
  end
  @message = WcoEmail::Message.create!({
    stub:         stub,
    conversation: conv,
    lead:         lead,
    message_id:     message_id,
    in_reply_to_id: in_reply_to_id,
    object_key:     stub.object_key,
    subject: subject,
    date:    the_mail.date,
    from:  from,
    froms: the_mail.from,
    to:  the_mail.to ? the_mail.to[0] : nil,
    tos: the_mail.to,
    cc:  the_mail.cc ? the_mail.cc[0] : nil,
    ccs: the_mail.cc,
  })
  # puts! @message, '@message'
  ## Parts
  the_mail.parts.each do |part|
    @message.churn_subpart( part )
  end
  @message.save
  if the_mail.parts.length == 0
    body = the_mail.body.decoded.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?')
    if the_mail.content_type&.include?('text/html')
      @message.part_html = body
    elsif the_mail.content_type&.include?('text/plain')
      @message.part_html = "<pre>#{body}</pre>"
    elsif the_mail.content_type.blank?
      @message.part_html = "<pre>#{body}</pre>"
    else
      @message.logs.push "mail body of unknown type: #{the_mail.content_type}"
      @message.part_html = "<pre>#{body}</pre>"
    end
    @message.save
  end
  ## Attachments, which are parts (omit!)
  # the_mail.attachments.each do |att|
  #   @message.save_attachment( att )
  # end
  if !@message.save
    puts! @message.errors.full_messages.join(", "), "Could not save @message"
  end
  the_mail.cc&.each do |cc|
    Wco::Lead.find_or_create_by_email( cc )
  end
  conv.update_attributes({
    status:      WcoEmail::Conversation::STATUS_UNREAD,
    latest_at:   the_mail.date || Time.now.to_datetime,
    from_emails: ( conv.from_emails + the_mail.from ).uniq,
    preview:     @message.preview_str,
  })
  ##
  ## Tags
  ##
  conv.tags.push Wco::Tag.inbox
  conv.tags.push stub.tags
  conv.save
  ## Actions & Filters
  email_filters = WcoEmail::EmailFilter.all
  email_filters.each do |filter|
    reason = nil
    if filter.from_regex.present? && @message.from.downcase.match( filter.from_regex )
      reason = 'from_regex'
    end
    if filter.from_exact.present? && @message.from.downcase.include?( filter.from_exact.downcase )
      reason = 'from_exact'
    end
    if filter.body_exact.present? && @message.part_html&.include?( filter.body_exact )
      reason = 'body_exact'
    end
    if filter.subject_regex.present? && @message.subject.match( filter.subject_regex )
      reason = 'subject_regex'
    end
    if filter.subject_exact.present? && @message.subject.downcase.include?( filter.subject_exact.downcase )
      reason = 'subject_exact'
    end
    if reason
      puts! "Applying filter #{filter} to conv #{@message.conversation} for matching #{reason}" if DEBUG
      ## skip
      skip_reason = nil
      if filter.skip_to_exact.present? && @message.to&.downcase.include?( filter.skip_to_exact.downcase )
        skip_reason = 'skip_to_exact'
      end
      if filter.skip_from_regex.present? && @message.from.downcase.match( filter.skip_from_regex )
        skip_reason = 'skip_from_regex'
      end
      if skip_reason
        puts! "NOT Applying filter #{filter} to conv #{@message.conversation} for matching #{skip_reason}" if DEBUG
      else
        @message.apply_filter( filter )
      end
    end
  end
  stub.update_attributes({ status: WcoEmail::MessageStub::STATUS_PROCESSED })
  ## Notification
  config = JSON.parse(stub.config)
  if config['skip_notification']
    ;
  else
    ## 2024-07-30 I'm no longer sending these to google.
    ## 2024-11-03 restarted sending.
    conv = WcoEmail::Conversation.find( conv.id )
    if conv.tags.include? Wco::Tag.inbox
      out = WcoEmail::ApplicationMailer.forwarder_notify( @message.id.to_s )
      Rails.env.production? ? out.deliver_later : out.deliver_now
    end
  end
  puts 'ok'
end

def mbox2stubs mbox_path, tagname:, skip:

def mbox2stubs mbox_path, tagname:, skip:
  puts 'Starting...'
  skip ||= 0
  @count = 1
  @client ||= Aws::S3::Client.new({
    region:            ::S3_CREDENTIALS[:region_ses],
    access_key_id:     ::S3_CREDENTIALS[:access_key_id_ses],
    secret_access_key: ::S3_CREDENTIALS[:secret_access_key_ses],
  })
  @tag = Wco::Tag.find_or_create_by({ slug: tagname })
  message    = nil
  File.readlines(mbox_path, encoding: "ISO8859-1" ).each do |line|
    if (line.match(/\AFrom /))
      if message
        if skip < @count
          save_mbox_to_m3 message
          print "#{@count}."
        else
          print "s-#{@count}."
        end
        @count += 1
      end
      message = ''
    else
      message << line.sub(/^\>From/, 'From')
    end
  end
  if message
    if skip < @count
      save_mbox_to_m3 message
      print "#{@count}."
    else
      print "s-#{@count}."
    end
    @count += 1
  end
  message = ''
end

def save_mbox_to_m3 message

# This only saves a local message from mbox to s3.
def save_mbox_to_m3 message
  the_mail = Mail.new(message)
  key      = the_mail.message_id || "no-key-#{Time.now.to_i}.#{rand(1000)}"
  @stub = WcoEmail::MessageStub.create({
    bucket:      ::S3_CREDENTIALS[:bucket_ses],
    object_key:  key,
    status:      WcoEmail::MessageStub::STATUS_PENDING,
    tags:        [ @tag ],
  })
  if @stub.persisted?
    @client.put_object({
      body: message,
      bucket: ::S3_CREDENTIALS[:bucket_ses],
      key: key,
    })
  else
    msg = @stub.errors.full_messages.join(", ")
    puts! msg
    Wco::Log.create({
      message:    "Stub duplicate object_key: #{key}",
      class_name: 'WcoEmail::MessageStub',
      raw_json:   @stub.attributes.to_json,
      tags:       [ @tag ],
    })
  end
end