# frozen_string_literal: true

class AppearanceRelease < ApplicationRecord
  include Confirmable
  include Contractable
  include Exploitable
  include Notable
  include Releasable
  include Searchable
  include Signable
  include Syncable
  include Taggable
  include PersonName
  include GuardianPhotoable
  include GuardianName

  has_one_attached :person_photo

  composed_of :person_address,
              class_name: 'Address',
              mapping: [
                %w[person_address_street1 street1],
                  %w[person_address_street2 street2],
                  %w[person_address_city city],
                  %w[person_address_state state],
                  %w[person_address_zip zip],
                  %w[person_address_country country]
              ]

  # These validations apply to all releases
  validates :person_email, email: true, allow_blank: true
  validates :person_first_name, :person_last_name, presence: true

  scope :order_by_name, -> { order(:person_last_name) }

  def self.random_contract_number
    rand(1_000_000..9_999_998) # random 7 digit number
  end

  # We don't care for the argument but method WILL receive option name
  # when called from inside with_option block, hence * argument
  def self.face_photo_acceptable_content_types(*)
    ['image/png', 'image/jpeg']
  end

  def self.acceptable_import_file_extensions
    ['.png', '.jpeg', '.jpg', '.pdf']
  end

  # These validations apply to releases being signed by a minor
  with_options if: :minor? do
    validates :guardian_first_name, :guardian_last_name, presence: true
    validates :guardian_email, email: true, allow_blank: true
  end

  validates :person_photo, content_type: face_photo_acceptable_content_types

  # These validations apply to releases created natively by the system (i.e. not imported from elsewhere)
  with_options on: :native do
    validates :signature, attached: true
    validates :person_photo, attached: true, content_type: face_photo_acceptable_content_types
    validate :person_photo_is_acceptable, if: :new_record? # Only validate photos on new releases
  end

  def contract_or_photo_is_attached
    return if person_photo.attached? || contract.attached?

    errors[:base] << I18n.t('appearance_releases.index.imported_appearance_release_missing_attachment')
  end

  # These validations apply to releases imported to the system from an outside source
  with_options on: :non_native do
    validate :contract_or_photo_is_attached
    validates :person_photo, content_type: face_photo_acceptable_content_types
  end

  scope :with_person_photo,                 -> { joins(:person_photo_attachment) }
  scope :with_person_photo_and_contract,    -> { joins(:person_photo_attachment, :contract_attachment) }
  scope :without_person_photo_or_contract,  -> { where.not(id: with_person_photo_and_contract) }
  scope :complete,                          -> { with_person_photo_and_contract }
  scope :incomplete,                        -> { without_person_photo_or_contract }
  scope :having_no_person_photo,            -> { left_joins(:person_photo_attachment).group(:id).having('COUNT(active_storage_attachments) = 0') }
  scope :with_person_name,                  ->(name) { where('person_first_name ILIKE ? OR person_last_name ILIKE ?', "%#{name}%") }

  searchable_on %i[
    person_first_name
    person_last_name
    person_address_old
    person_address_street1
    person_address_street2
    person_address_city
    person_address_state
    person_address_zip
    person_address_country
    person_email
    person_phone
  ]

  def person_address
    return self.person_address_old if self.person_address_old.present?

    Address.new(
        self.person_address_street1,
        self.person_address_street2,
        self.person_address_city,
        self.person_address_state,
        self.person_address_zip,
        self.person_address_country
    ).to_s(format: :full)
  end

  # All releases must respond to the following messages
  def name
    person_name
  end

  def filename_suffix
    "#{person_last_name} #{person_first_name}"
  end

  def photo
    person_photo
  end

  def photos
    photo.attached? ? [photo] : []
  end

  def contact_person
    @contact_person ||= Contact.new(name, person_address, person_email, person_phone)
  end

  def uses_edl?
    true
  end

  def contract_file_name
    "#{project.name.parameterize}_#{contract_template.release_type}_#{(signed_at || created_at).strftime('%Y.%m.%d')}_#{release_number}_#{filename_suffix.parameterize}"
  end

  private

  # Validates the quality of the person photo
  def person_photo_is_acceptable
    return unless person_photo.attached?

    # Call a remote API to perform the validation
    image_validation = BrayniacAI::Validation.create(bucket_name: ENV['AWS_BUCKET'], object_name: person_photo.key)

    unless image_validation.valid
      errors.add(:person_photo, image_validation.error)
    end
  rescue ActiveResource::ConnectionError => e
    # TODO
    Rails.logger.error(e)
  end
end
