class Contact < ApplicationRecord
  include Base::Contact
  include Personable
  include Validatable
  include Formattable

  attr_accessor :admission

  enum gender: { male: 1, female: 2 }
  enum marital_status: {
    unspecified: 0,
    married: 1,
    separated: 2,
    divorced: 3,
    remarried: 4,
    widowed: 5,
    single: 6
  }

  belongs_to :school, inverse_of: :contacts,
    primary_key: :SchoolID, foreign_key: :SchoolID
  belongs_to :title, inverse_of: :contacts,
    primary_key: :TitleID, foreign_key: :TitleID,
    optional: true
  belongs_to :user, foreign_key: :UserID, optional: true, inverse_of: :contact
  belongs_to :country, class_name: 'IsoCountry', optional: true
  belongs_to :company, inverse_of: :contacts, class_name: 'Company', foreign_key: :CCID,
    optional: true
  belongs_to :author, class_name: 'User', foreign_key: :AuthorID, inverse_of: :contacts,
    optional: true

  has_many :contact_families, inverse_of: :contact, primary_key: :ContactID,
    foreign_key: :ContactID, dependent: :destroy
  has_many :user_contacts, foreign_key: :ContactID, inverse_of: :contact, dependent: :destroy
  has_many :call_notes, class_name: 'ContactCallNote', foreign_key: :ContactID,
    inverse_of: :contact, dependent: :destroy

  has_many :families, through: :contact_families
  has_many :primary_students, through: :families
  has_many :admission_contact_revisions, through: :contact_families

  has_many :financial_aid_contacts, dependent: :destroy
  has_many :category_contacts, class_name: 'ContactCategoryContact', foreign_key: :ContactID,
    dependent: :destroy, inverse_of: :contact
  has_many :categories, through: :category_contacts, source: :category, dependent: :destroy
  has_many :additional_values, class_name: 'ContactAdditionalValue', foreign_key: :ContactID,
    dependent: :destroy, inverse_of: :contact
  has_many :email_addresses, class_name: '::ContactEmail', foreign_key: :associated_id,
    as: :associated, dependent: :destroy, inverse_of: :contact
  has_many :batch_email_recipients, class_name: '::Communication::BatchEmailRecipient',
    foreign_key: :associated_id, as: :associated, dependent: :destroy, inverse_of: :associated
  has_many :connection_logs, class_name: '::ConnectionLog', as: :associated, dependent: :destroy


  has_one :primary_email_address, -> { where(primary: true) }, class_name: '::ContactEmail',
    foreign_key: :associated_id, as: :associated, dependent: :destroy, inverse_of: :contact
  has_one :payjunction_contact, foreign_key: :person_id,
    class_name: 'Payjunction::Contact', inverse_of: :contact
  has_one :communication_user, -> { contact }, class_name: '::Communication::User',
    foreign_key: :associated_id, dependent: :destroy, inverse_of: :associated

  associations_for namespace: 'EdFi' do |a|
    a.has_many :logs, as: :associated, inverse_of: :associated
  end

  delegate :admission_registration_fields, to: :school

  validates :first_name, :last_name, presence: true
  validates :address, :address_ext, :country, length: { maximum: 64 }
  validates :city, :state, length: { maximum: 32 }
  validates :zip, length: { maximum: 10 }
  validates :home_phone, :cell_phone, :work_phone, :work_phone_2, :fax_phone,
    length: { maximum: 24 }
  validates :email, presence: true, length: { maximum: 128 },
    format: { with: URI::MailTo::EMAIL_REGEXP }, if: :admission

  validate :validate_admission_values, if: :admission

  after_initialize -> { self.country_id = school.country_id }, unless: :country_id?

  before_update :remove_from_communication_user

  before_save :update_legacy_country, if: -> { country_id_changed? }

  after_save :tep_update, if: -> { school.school_config.tep_integration? }

  after_commit :stream_update
  after_destroy :stream_destroy

  accepts_nested_attributes_for :contact_families, update_only: true

  scope :ordered, -> { order(:last_name, :first_name) }
  scope :primary, ->(flag=true) { where('FamilyParents.PrimaryParent = 1') if flag }
  scope :emergency, ->(flag=true) { where('FamilyParents.Emergency = 1') if flag }
  scope :with_family, ->(ids) { where(Families: { FamilyID: ids }) if ids.present? }

  scope :by_primary_email_address, ->(flag) do
    return unless flag

    joins(:primary_email_address)
  end

  scope :by_categories, ->(ids) do
    joins(:categories).where(ContactCatagories: { CatagoryID: ids }) if ids
  end

  def self.with_non_primary_emergency
    find_by('FamilyParents.PrimaryParent = false AND FamilyParents.Emergency = true')
  end

  def find_or_create_paya_contact(family)
    contact = Paya::ContactService.call(school, :show, self)['contacts'].first
    return contact['id'] if contact

    Paya::ContactService.call(school, :create, self, family)['contact']['id']
  end

  private
    def remove_from_communication_user
      return unless communication_user

      [:home_phone, :work_phone, :cell_phone].each do |phone|
        next unless send("#{phone}_changed?")

        previous_number = send("#{phone}_was").tr('^0-9', '')
        if previous_number == communication_user.voice_phone
          communication_user.update(voice_phone: '')
        end

        if previous_number == communication_user.message_phone
          communication_user.update(message_phone: '')
        end
      end
    end

    def validate_admission_values
      required_fields = ::Admission::RegistrationField::REQUIRED_FIELDS
      fields = admission_registration_fields.by_form_fields.where(required: true).pluck(:field)
      fields.each do |field|
        next if required_fields.include?(field)

        field = 'zip' if field == 'zip_code'
        field = 'title' if field == 'title_id'
        errors.add(field, 'cannot be blank') if public_send(field).blank?
      end
    end

    def update_legacy_country
      self.Country = country&.name || ''
    end

    def stream_update
      Notification::ContactsJob.perform_async(id)
    end

    def stream_destroy
      ActionCable.server.broadcast("employee_contacts_#{school_id}", { action: 'destroy', id: id })
    end

    def tep_update
      return if primary_email_address.nil?

      Tep::ContactService.call(school, id)
    end
end
