# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
module QueryTickets

  def self.attendees_expr(event_id, query)
    expr = Qexpr.new
      .from('tickets')
      .where("coalesce(tickets.deleted, FALSE) = FALSE")
      .left_outer_join("event_discounts", "event_discounts.id=tickets.event_discount_id")
      .left_outer_join(
        Qexpr.new.select("*")
        .from(:supporters).group_by("id").as("supporters"),
        'tickets.supporter_id=supporters.id'
      )
      .left_outer_join("charges", "charges.id=tickets.charge_id")
      .left_outer_join(
        Qexpr.new.select("charge_id", "SUM(coalesce(amount, 0)) AS amount")
        .from(:refunds)
        .group_by(:charge_id)
        .as(:refunds),
        "refunds.charge_id=charges.id"
      )
      .left_outer_join(
        Qexpr.new.select("id", "name", "amount")
        .from(:ticket_levels).group_by("id").as("ticket_levels"),
        'tickets.ticket_level_id=ticket_levels.id'
      )
      .left_outer_join(
          Qexpr.new.select('token', 'tokenizable_id').from(:source_tokens).group_by( 'token', 'tokenizable_id').as('source_tokens'),
          'tickets.source_token_id=source_tokens.token'
      )
      .left_outer_join(
          # TODO this does not support anything other than cards!
        Qexpr.new.select('id', 'name').from(:cards).group_by('id', 'name').as('cards'),
        'source_tokens.tokenizable_id = cards.id'
      )
      .left_outer_join(
        Qexpr.new.select('supporter_id', 'MAX(event_id) AS event_id', 'SUM(amount) AS total_amount')
        .from(:donations).where("event_id=$id", id: event_id).group_by("supporter_id").as(:donations),
        "donations.supporter_id=supporters.id AND donations.event_id=$id", id: event_id
      )
      .where('tickets.event_id=$id', id: event_id)
      .order_by('tickets.bid_id DESC')
    if query[:search].present?
      query[:search] = "%#{query[:search].downcase.split(' ').join('%')}%"
      expr = expr.where(%Q(
            lower(supporters.name)    LIKE $search
         OR lower(supporters.email)   LIKE $search
         OR lower(ticket_levels.name) LIKE $search
       ), search: '%' + query[:search] + '%')
    end
    if ['asc', 'desc'].include? query[:sort_attendee]
      expr = expr.order_by("lower(supporters.name) #{query[:sort_attendee]} NULLS LAST")
    end
    if ['asc', 'desc'].include? query[:sort_id]
      expr = expr.order_by("tickets.bid_id #{query[:sort_id]}")
    end
    if ['asc', 'desc'].include? query[:sort_note]
      expr = expr.order_by("lower(tickets.note) #{query[:sort_note]} NULLS LAST")
    end
    if ['asc', 'desc'].include? query[:sort_ticket_level]
      expr = expr.order_by("lower(ticket_levels.name) #{query[:sort_ticket_level]} NULLS LAST")
    end
    if ['asc', 'desc'].include? query[:sort_donation]
      expr = expr.order_by("total_donations #{query[:sort_donation]} NULLS LAST")
    end
    return expr
  end


  def self.attendees_list(event_id, query)
    limit = 30
    offset = Qexpr.page_offset(limit, query[:page])

    data = Psql.execute(
      attendees_expr(event_id, query)
      .limit(limit).offset(offset)
      .select(*attendees_list_selection)
    )

    total_count = Psql.execute(
      Qexpr.new.select("COUNT(ts)")
        .from(attendees_expr(event_id, query)
        .remove(:order_by).select('tickets.id'), 'ts')
    ).first['count']

    #TODO this worries me. Seems like a recipe for slow returns... perhaps some caching of the tokens every so often?
    data.each{|i|
      unless (i['source_token_id'] && QuerySourceToken.source_token_unexpired?(SourceToken.find(i['source_token_id'])))
        i['source_token_id'] = nil
      end
    }

    return {
      data: data,
      total_count: total_count,
      remaining: Qexpr.remaining_count(total_count, limit, query[:page])
    }
  end


  def self.for_export(event_id, query)
    Psql.execute_vectors(
      attendees_expr(event_id, query)
      .select([
        "tickets.bid_id AS id",
        "ticket_levels.name AS ticket_level",
        "MONEY((coalesce(charges.amount, 0) - coalesce(refunds.amount, 0)) / 100.0) AS ticket_cost",
        "MONEY(coalesce(donations.total_amount, 0) / 100.0) AS total_donations",
        "tickets.quantity",
        "tickets.checked_in AS \"Checked In?\"",
        "tickets.note",
        "CASE WHEN event_discounts.id IS NULL THEN 'None' ELSE concat(event_discounts.name, ' (', event_discounts.percent, '%)') END AS \"Discount\"",
        "CASE WHEN tickets.card_id IS NULL OR tickets.card_id = 0 THEN '' ELSE 'YES' END AS \"Card Saved?\""
      ].concat(QuerySupporters.supporter_export_selections))
    )
  end


  def self.attendees_list_selection
    ['tickets.id',
     'tickets.bid_id',
     'tickets.checked_in',
     'tickets.quantity',
     'tickets.note',
     'tickets.source_token_id',
     'ticket_levels.name AS ticket_level_name',
     '(coalesce(charges.amount, 0) - coalesce(refunds.amount, 0)) AS total_paid',
     'ticket_levels.id AS ticket_level_id',
     'ticket_levels.amount AS ticket_level_amount',
     'event_discounts.percent AS discount_percent',
     'supporters.id AS supporter_id',
     'supporters.name AS name',
     'supporters.email AS email',
     'coalesce(donations.total_amount, 0) AS total_donations',
     'source_tokens.token AS token',
     'cards.name AS card_name'
    ]
  end

  def self.for_event_activities(event_id)
    selects = ["
      CASE 
        WHEN supporters.anonymous='t' 
          OR supporters.name='' 
          OR supporters.name IS NULL 
        THEN 'A supporter' 
        ELSE supporters.name 
      END AS supporter_name", 
      'tickets.quantity', 'tickets.created_at']
    return Qx.select(selects.join(','))
      .from(:tickets)
      .left_join(:supporters, 'tickets.supporter_id=supporters.id')
      .where('tickets.event_id=$id', id: event_id)
      .order_by("tickets.created_at desc")
      .limit(15)
      .execute
  end

end