# All cards have one (and only one) of these three states: real, virtual, and unknown.
#
# - *real* cards are stored in the database (but not in the trash) and have a unique id.
# - *virtual* cards are not real, but they act real based on rules. For example,
#   Home+*editors does a search for all the users who have edited the "Home" card.
#   There are many other similar cards that search for things like references, children,
#   etc. But we don't store all these cards in the database; we generate them dynamically
#   based on the names.
# - *unknown* cards are everything else.
#
# These states are frequently grouped as follows:
#
# - *known* cards are either _real_ or _virtual_
# - *new* (or *unreal*) cards are either _unknown_ or _virtual_

# extends Card Class
module ClassMethods
  def real? mark
    quick_fetch(mark).present?
  end
  alias_method :exist?, :real?
  alias_method :exists?, :real?

  def known? mark
    fetch(mark).present?
  end
end

# @return [Symbol] :real, :virtual, or :unknown
def state anti_fishing=true
  case
  when !known? || (anti_fishing && !ok?(:read)) then :unknown
  when real?                                    then :real
  when virtual?                                 then :virtual
  else :wtf
  end
end

# @return [True/False]
def real?
  !unreal?
end

# Virtual cards are structured, compound cards that are not stored in the database. You
# can create virtual cards with structure rules.
#
# Some cards with hard-coded content will also override the #virtual? method. This
# is established practice, but it is NOT advisable to override any of the other
# state methods.
#
# @return [True/False]
def virtual?
  if @virtual.nil?
    @virtual = real? || name.simple? ? false : structure.present?
  end
  @virtual
end

# @return [True/False]
def unknown?
  !known?
end

# @return [True/False]
def known?
  real? || virtual?
end

# @return [True/False]
def new?
  (new_record? ||         # not yet in db (from ActiveRecord) or
    !@from_trash.nil?) && # in process of restoration from trash, but
    !trash?               # not in trash
end
alias_method :new_card?, :new?
alias_method :unreal?, :new?

def purity
  case
  when new?      then :new
  when pristine? then :pristine
  else                :altered
  end
end

# has not been edited directly by human users.  bleep blorp.
def pristine?
  return true if new_card?
  return false if subcards? && subcards.cards.find(&:altered?)
  return true if (created_at == updated_at) && (creator_id == DeckoBotID)

  !user_changes?
end

def altered?
  !pristine?
end

def user_changes?
  actions.joins(:act).where("card_acts.actor_id != ?", DeckoBotID).exists?
end
