# == Schema Information
#
# Table name: track_domains
#
#  id                     :integer          not null, primary key
#  uuid                   :string(255)
#  server_id              :integer
#  domain_id              :integer
#  name                   :string(255)
#  dns_checked_at         :datetime
#  dns_status             :string(255)
#  dns_error              :string(255)
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#  ssl_enabled            :boolean          default(TRUE)
#  track_clicks           :boolean          default(TRUE)
#  track_loads            :boolean          default(TRUE)
#  excluded_click_domains :text(65535)
#

require 'resolv'

class TrackDomain < ApplicationRecord

  include HasUUID

  belongs_to :server
  belongs_to :domain

  validates :name, :presence => true, :format => {:with => /\A[a-z0-9\-]+\z/}, :uniqueness => {:scope => :domain_id, :message => "is already added"}
  validates :domain_id, :uniqueness => {:scope => :server_id, :message => "already has a track domain for this server"}
  validate :validate_domain_belongs_to_server

  scope :ok, -> { where(:dns_status => 'OK')}

  after_create :check_dns, :unless => :dns_status
  after_create :create_ssl_certificate_if_missing
  after_destroy :delete_ssl_certificate_when_not_in_use

  before_validation do
    self.server = self.domain.server if self.domain && self.server.nil?
  end

  def full_name
    "#{name}.#{domain.name}"
  end

  def excluded_click_domains_array
    @excluded_click_domains_array ||= excluded_click_domains ? excluded_click_domains.split("\n").map(&:strip) : []
  end

  def dns_ok?
    self.dns_status == 'OK'
  end

  def check_dns
    result = self.domain.resolver.getresources(self.full_name, Resolv::DNS::Resource::IN::CNAME)
    records = result.map { |r| r.name.to_s.downcase }
    if records.empty?
      self.dns_status = 'Missing'
      self.dns_error = "There is no record at #{self.full_name}"
    else
      if records.size == 1 && records.first == Postal.config.dns.track_domain
        self.dns_status = 'OK'
        self.dns_error = nil
      else
        self.dns_status = 'Invalid'
        self.dns_error = "There is a CNAME record at #{self.full_name} but it points to #{records.first} which is incorrect. It should point to #{Postal.config.dns.track_domain}."
      end
    end
    self.dns_checked_at = Time.now
    self.save!
    dns_ok?
  end

  def has_ssl?
    ssl_certificate && ssl_certificate.active?
  end

  def use_ssl?
    ssl_enabled? && has_ssl?
  end

  def ssl_certificate
    @ssl_certificate ||= TrackCertificate.where(:domain => self.full_name).first
  end

  def validate_domain_belongs_to_server
    if self.domain && ![self.server, self.server.organization].include?(self.domain.owner)
      errors.add :domain, "does not belong to the server or the server's organization"
    end
  end

  def create_ssl_certificate_if_missing
    unless TrackCertificate.where(:domain => self.full_name).exists?
      TrackCertificate.create!(:domain => self.full_name)
    end
  end

  def delete_ssl_certificate_when_not_in_use
    others = TrackDomain.includes(:domain).where(:name => self.name, :domains => {:name => self.domain.name})
    if others.empty?
      TrackCertificate.where(:domain => self.full_name).destroy_all
    end
  end

end
