class HelpdeskTicket < ActiveRecord::Base
  HELPDESK_EMAIL_SOURCE = 0
  HELPDESK_WEB_SOURCE = 1
  HELPDESK_PHONE_SOURCE = 2
  HELPDESK_TWITTER_SOURCE = 3
  HELPDESK_CONVERSATION_SOURCE = 4

  SEND_AS_NOTIFICATION = 1
  SEND_AS_MESSAGE = 2

  attr_accessible :vote, :vote_comment,:from_address,
                  :to_address, :cc_address, :ticket_date,
                  :message_id, :is_incoming, :customer, :issue, :source, :contact_id, :ticket_time

  attr_accessor :ticket_time

  unloadable
  belongs_to :customer, :class_name => 'Contact', :foreign_key => 'contact_id'
  belongs_to :issue
  has_one :message_file, :class_name => "Attachment", :as  => :container, :dependent => :destroy

  acts_as_attachable :view_permission => :view_issues,
                     :delete_permission => :edit_issues


  if ActiveRecord::VERSION::MAJOR >= 4
    acts_as_activity_provider :type => 'helpdesk_tickets',
                              :permission => :view_helpdesk_tickets,
                              :timestamp => "#{table_name}.ticket_date",
                              :author_key => "#{Issue.table_name}.author_id",
                              :scope => eager_load(:issue => :project)
  else
    acts_as_activity_provider :type => 'helpdesk_tickets',
                              :permission => :view_helpdesk_tickets,
                              :timestamp => "#{table_name}.ticket_date",
                              :author_key => "#{Issue.table_name}.author_id",
                              :find_options => {:include => {:issue => :project}}
  end

  acts_as_event :datetime => :ticket_date,
                :project_key => "#{Project.table_name}.id",
                :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue_id}},
                :type => Proc.new {|o| 'icon icon-email' + (o.issue.closed? ? ' closed' : '') if o.issue },
                :title => Proc.new {|o| "##{o.issue.id} (#{o.issue.status}): #{o.issue.subject}" if o.issue },
                :author => Proc.new {|o|  o.customer},
                :description => Proc.new{|o| o.issue.description if o.issue}

  accepts_nested_attributes_for :customer

  after_create :set_ticket_private
  before_save :calculate_metrics
  validates_presence_of :customer, :ticket_date

  def initialize(attributes=nil, *args)
    super
    if new_record?
      # set default values for new records only
      self.ticket_date ||= Time.now
      self.source ||= HelpdeskTicket::HELPDESK_EMAIL_SOURCE
    end
  end

  def ticket_time
    self.ticket_date.to_s(:time) unless self.ticket_date.blank?
  end

  def ticket_time=(val)
    if !self.ticket_date.blank? && val.to_s.gsub(/\s/, "").match(/^(\d{1,2}):(\d{1,2})$/)
      timezone = ticket_date.try(:time_zone).try(:name) || Time.zone.name
      self.ticket_date = ActiveSupport::TimeZone.new(timezone).local_to_utc(self.ticket_date.utc).
                                                 in_time_zone(timezone).
                                                 change({:hour => $1.to_i % 24, :min => $2.to_i % 60})
    end
  end

  def recalculate_events
    unless issue.closed?
      close_journal_id = nil
    end
  end

  def available_addresses
    @available_addresses ||= ([self.default_to_address] | self.customer.emails.map{|e| e} | [self.from_address.blank? ? nil : self.from_address.downcase.strip]).compact.uniq if self.customer
  end

  def default_to_address
    return last_response_address if last_journal_message && last_journal_message.is_incoming?
    address = self.from_address.blank? ? "" : self.from_address.downcase.strip
    self.customer.emails.include?(address) ? address : self.customer.primary_email
  end

  def last_reply_customer
    return customer unless default_to_address
    customer.primary_email == default_to_address ? customer : Contact.find_by_emails([default_to_address]).first
  end

  def cc_addresses
    @cc_addresses = ((self.issue.contacts ? self.issue.contacts.map(&:primary_email) : []) | cc_address.to_s.split(',')).compact.uniq
  end

  def project
    issue.project if issue
  end

  def author
    issue.author if issue
  end

  def customer_name
  	customer.name if customer
  end

  def responses
    @responses ||= JournalMessage.
      joins(:journal).
      where(:journals => {:journalized_id => self.issue_id}).
      order("#{JournalMessage.table_name}.message_date ASC")
  end

  def reaction_date
    @reaction_date ||= self.issue.journals.
      joins(:journal_message).
      where("#{JournalMessage.table_name}.journal_id IS NULL OR #{JournalMessage.table_name}.is_incoming = ?", false).
      order("#{Journal.table_name}.created_on ASC").
      first.
      try(:created_on).try(:utc)
  end

  def response_addresses
    responses.where(:is_incoming => true).map { |response| response.from_address }.uniq
  end

  def first_response_date
    @first_response_date ||= responses.select {|r| !r.is_incoming? }.first.try(:message_date).try(:utc)
  end

  def last_response_time
    @last_response_time ||= last_journal_message && last_journal_message.is_incoming? && !self.issue.closed? ? last_journal_message.message_date.utc : nil
  end

  def last_response_address
    response_addresses.last
  end

  def last_agent_response
    @last_agent_response ||= responses.select { |r| !r.is_incoming? }.last
  end

  def last_journal_message
    @last_journal_message ||= responses.last
  end

  def last_customer_response
    @last_customer_response ||= responses.select { |r| r.is_incoming? }.last
  end

  def average_response_time

  end

  def ticket_source_name
    case self.source
      when HelpdeskTicket::HELPDESK_EMAIL_SOURCE then l(:label_helpdesk_tickets_email)
      when HelpdeskTicket::HELPDESK_PHONE_SOURCE then l(:label_helpdesk_tickets_phone)
      when HelpdeskTicket::HELPDESK_WEB_SOURCE then l(:label_helpdesk_tickets_web)
      when HelpdeskTicket::HELPDESK_TWITTER_SOURCE then l(:label_helpdesk_tickets_twitter)
      when HelpdeskTicket::HELPDESK_CONVERSATION_SOURCE then l(:label_helpdesk_tickets_conversation)
      else ""
    end
  end

  def ticket_source_icon
    case self.source
      when HelpdeskTicket::HELPDESK_EMAIL_SOURCE then "icon-email"
      when HelpdeskTicket::HELPDESK_PHONE_SOURCE then "icon-call"
      when HelpdeskTicket::HELPDESK_WEB_SOURCE then "icon-web"
      when HelpdeskTicket::HELPDESK_TWITTER_SOURCE then "icon-twitter"
      else "icon-helpdesk"
    end
  end

  def content
    issue.description if issue
  end

  def customer_email
    customer.primary_email if customer
  end

  def last_message
    @last_message ||= JournalMessage.eager_load(:journal => :issue).where(:issues => {:id => issue.id}).order("#{Journal.table_name}.created_on ASC").last || self
  end

  def last_message_date
    last_message.is_a?(HelpdeskTicket) ? self.ticket_date : last_message.message_date if last_message
  end

  def ticket_date
    return nil if super.blank?
    zone = User.current.time_zone
    zone ? super.in_time_zone(zone) : (super.utc? ? super.localtime : super)
  end

  def token
    Digest::MD5.hexdigest("#{issue.id}:#{self.ticket_date.utc}:#{Rails.application.config.secret_token}")
  end

  def calculate_metrics
    self.reaction_time = reaction_date - ticket_date.utc if reaction_date && ticket_date
    self.first_response_time = first_response_date - ticket_date.utc if first_response_date && ticket_date
    self.resolve_time = self.issue.closed? ? self.issue.closed_on - ticket_date.utc : nil if ticket_date && self.issue.closed_on && last_agent_response
    self.last_agent_response_at = last_agent_response.message_date if last_agent_response
    self.last_customer_response_at = last_customer_response.message_date if last_customer_response
  end

  def self.vote_message(vote)
    case vote.to_i
    when 0
      l(:label_helpdesk_mark_notgood)
    when 1
      l(:label_helpdesk_mark_justok)
    when 2
      l(:label_helpdesk_mark_awesome)
    else
      ""
    end
  end

  def update_vote(new_vote, comment = nil)
    old_vote = vote
    old_vote_comment = vote_comment
    if update_attributes(:vote => new_vote, :vote_comment => comment )
      if old_vote != vote || old_vote_comment != vote_comment
        journal = Journal.new(:journalized => issue, :user => User.current)
        journal.details << JournalDetail.new(:property => 'attr',
                                              :prop_key => 'vote',
                                              :old_value => old_vote,
                                              :value => vote) if old_vote != vote
        journal.details << JournalDetail.new(:property => 'attr',
                                              :prop_key => 'vote_comment',
                                              :old_value => old_vote_comment,
                                              :value => vote_comment) if old_vote_comment != vote_comment
        journal.save
      end
    end
  end

  def self.autoclose(project)
    return unless RedmineHelpdesk.autoclose_tickets_after > 0
    issues = Issue.includes(:helpdesk_ticket).where(:project_id => project.id).
                                           where(:status_id => RedmineHelpdesk.autoclose_from_status).
                                           where('created_on < ?', Time.now - RedmineHelpdesk.autoclose_time_interval)
    issues.find_each do |issue|
      issue.init_journal(User.anonymous)
      issue.current_journal.notes = I18n.t('label_helpdesk_autoclosed_ticket')
      issue.status_id = RedmineHelpdesk.autoclose_to_status
      issue.save
    end
  end

  private

  def set_ticket_private
    return unless RedmineHelpdesk.settings["helpdesk_assign_contact_user"].to_i > 0
    issue.assign_attributes(:is_private => true) if RedmineHelpdesk.settings["helpdesk_create_private_tickets"].to_i > 0
    issue.save unless issue.new_record?
  end
end
