class TicketType < ActiveRecord::Base
  belongs_to  :section
  belongs_to  :show
  belongs_to  :membership_type
  delegate    :chart, :to => :section
  has_many    :tickets

  after_save  { self.chart.upgrade_event unless self.chart.nil? }
  attr_accessible :name, :price, :limit, :description, :storefront, :box_office, :members, 
                  :membership_type_id, :tickets_per_membership, :member_ticket

  before_save :clear_membership_type_id

  validates :membership_type_id,    :presence => true, :if => "member_ticket?"

  def as_json(options = {})
    {
      "id"          => self.id,
      "name"        => self.name,
      "price"       => self.price,
      "limit"       => self.limit,
      "available"   => self.available,
      "description" => self.description 
    }
  end

  #
  # Returns Tickets
  #
  def available_tickets(ticket_limit = 4, member = nil)
    Ticket.available({:section_id     => self.section.id,
                      :ticket_type_id => nil }, 
                      [ticket_limit, self.available(member)].min)
  end

  #
  # Returns an integer number of tickets available
  #
  def available(channel = "storefront", member = nil)
    available_in_section = Ticket.where(:section_id => self.section, :state => :on_sale, :cart_id => nil, :ticket_type_id => nil).count

    return available_in_section if unlimited? && !self.member_ticket?

    available_measures = []
    available_measures << limit - committed.length - locked.length unless limit.nil?
    available_measures << available_in_section
    available_measures << available_to(member, available_in_section) if self.member_ticket? && channel == "storefront"

    [ available_measures.min, 0].max
  end

  def available_to(member, limit = 0)
    if member.nil?
      return 0 if self.member_ticket?
    elsif self.tickets_per_membership.nil?
      return limit
    else
      #how many member tickets has this member purchased for this show?
      member_tickets_purchased = member.member_tickets_purchased_for(self.show.event).count

      #how many tickets this member entitled to?
      tickets_entitled_to = member.memberships.current.where(:membership_type_id => self.membership_type_id).count * self.tickets_per_membership

      member_tickets_available = tickets_entitled_to - member_tickets_purchased
      member_tickets_available
    end    
  end

  def self.price_to_cents(price_in_dollars)
    (price_in_dollars.to_f * 100).to_i
  end

  # Each channel needs its own boolean column in the ticket types table.
  @@channels = { :storefront => "S", :box_office => "B", :members => "M"}
  @@channels.each do |channel_name, icon|
    attr_accessible channel_name
    self.class.send(:define_method, channel_name) do
      where(channel_name => true)
    end
  end

  def dup!
    TicketType.new(self.attributes.reject { |key, value| key == 'id' }, :without_protection => true)
  end

  def channels
    @@channels
  end

  def self.channels_for(organization)
    (organization.can? :access, :membership) ? @@channels : @@channels.except(:members)
  end

  def sold
    tickets.select {|t| t.sold?}
  end

  def committed
    tickets.select {|t| t.committed?}
  end

  def limit_to_s
    unlimited? ? "unlimited" : "#{self.limit} limit"
  end

  def unlimited?
    self.limit.nil?
  end

  def locked
    tickets.select {|t| t.locked?}
  end

  def comped
    tickets.select {|t| t.comped?}
  end

  def self.set_show(show)
    TicketType.joins(:section => :chart).where('charts.id = ?', show.chart_id).update_all(:show_id => show.id)
  end

  private
    def clear_membership_type_id
      self.membership_type_id = nil unless self.member_ticket?
    end
end