require 'time'

module RedmineHelpdesk
  module IssueApiSerializer
    module_function

    def serialize(issue)
      ticket = safe_send(issue, :helpdesk_ticket)
      return nil unless ticket

      contact = safe_send(ticket, :customer)
      contact_id = safe_send(ticket, :contact_id) || safe_send(contact, :id)
      contact_email = primary_email(contact)

      {
        :id => safe_send(ticket, :id),
        :contact_id => contact_id,
        :message_id => safe_send(ticket, :message_id),
        :source => safe_send(ticket, :source),
        :is_incoming => boolean_send(ticket, :is_incoming?),
        :from_address => safe_send(ticket, :from_address),
        :to_address => safe_send(ticket, :to_address),
        :cc_address => safe_send(ticket, :cc_address),
        :ticket_date => iso8601(safe_send(ticket, :ticket_date)),
        :contact => contact_payload(contact, contact_id, contact_email)
      }
    end

    def contact_payload(contact, contact_id, contact_email)
      return nil unless contact || contact_id || contact_email

      payload = {
        :id => contact_id,
        :name => safe_send(contact, :name),
        :company => safe_send(contact, :company),
        :email => contact_email
      }
      reject_blank_values(payload)
    end

    def primary_email(contact)
      email = safe_send(contact, :primary_email)
      return email unless blank?(email)

      emails = safe_send(contact, :emails)
      emails.respond_to?(:first) ? emails.first : nil
    end

    def iso8601(value)
      return nil if blank?(value)
      value.respond_to?(:utc) ? value.utc.iso8601 : value.to_s
    end

    def boolean_send(object, method_name)
      return nil unless object && object.respond_to?(method_name)
      object.public_send(method_name) ? true : false
    end

    def safe_send(object, method_name)
      return nil unless object && object.respond_to?(method_name)
      object.public_send(method_name)
    end

    def reject_blank_values(payload)
      result = {}
      payload.each do |key, value|
        result[key] = value unless blank?(value)
      end
      result
    end

    def blank?(value)
      value.nil? || (value.respond_to?(:empty?) && value.empty?)
    end
  end
end
