145 lines
4.0 KiB
Ruby
145 lines
4.0 KiB
Ruby
module Teams
|
|
# Elenco pubblico delle squadre con presenza su Match Live TV (diretta, replay o calendario).
|
|
class PublicDirectory
|
|
Entry = Struct.new(
|
|
:team,
|
|
:live_now,
|
|
:replay_count,
|
|
:upcoming_count,
|
|
:last_activity_at,
|
|
keyword_init: true
|
|
)
|
|
|
|
def self.call(q: nil, sport: nil, live: false, replays: false)
|
|
new(q: q, sport: sport, live: live, replays: replays).call
|
|
end
|
|
|
|
def initialize(q: nil, sport: nil, live: false, replays: false)
|
|
@q = q.to_s.strip
|
|
@sport = normalize_sport(sport)
|
|
@live = cast_bool(live)
|
|
@replays = cast_bool(replays)
|
|
end
|
|
|
|
def call
|
|
teams = base_teams
|
|
return [] if teams.empty?
|
|
|
|
entries = build_entries(teams)
|
|
entries = apply_toggle_filters(entries)
|
|
sort_entries(entries)
|
|
end
|
|
|
|
private
|
|
|
|
def normalize_sport(value)
|
|
key = value.to_s.strip
|
|
return nil if key.blank?
|
|
return nil unless Sports::Catalog.find_optional(key)
|
|
|
|
Sports::Catalog.normalize_key(key)
|
|
end
|
|
|
|
def cast_bool(value)
|
|
ActiveModel::Type::Boolean.new.cast(value)
|
|
end
|
|
|
|
def base_teams
|
|
scope = Team.visible.includes(:club).where(id: active_team_ids)
|
|
scope = scope.where(sport_key: @sport) if @sport
|
|
scope = apply_search(scope) if @q.present?
|
|
scope.to_a
|
|
end
|
|
|
|
def active_team_ids
|
|
live = live_team_ids
|
|
replays = replay_team_ids
|
|
upcoming = upcoming_team_ids
|
|
(live + replays + upcoming).uniq
|
|
end
|
|
|
|
def live_team_ids
|
|
StreamSession.broadcasting
|
|
.publicly_listed
|
|
.where(platform: "matchlivetv")
|
|
.joins(:match)
|
|
.distinct
|
|
.pluck("matches.team_id")
|
|
end
|
|
|
|
def replay_team_ids
|
|
Recording.ready.publicly_listed.joins(stream_session: :match).distinct.pluck("matches.team_id")
|
|
end
|
|
|
|
def upcoming_team_ids
|
|
broadcasting_match_ids = StreamSession.broadcasting.select(:match_id)
|
|
Match.scheduled_for_live
|
|
.where.not(id: broadcasting_match_ids)
|
|
.distinct
|
|
.pluck(:team_id)
|
|
end
|
|
|
|
def apply_search(scope)
|
|
term = "%#{ActiveRecord::Base.sanitize_sql_like(@q)}%"
|
|
scope.left_joins(:club, :matches).where(
|
|
"teams.name ILIKE :term OR clubs.name ILIKE :term OR matches.location ILIKE :term OR matches.opponent_name ILIKE :term",
|
|
term: term
|
|
).distinct
|
|
end
|
|
|
|
def build_entries(teams)
|
|
team_ids = teams.map(&:id)
|
|
live_set = live_team_ids.to_set
|
|
replay_counts = Recording.ready.publicly_listed
|
|
.joins(stream_session: :match)
|
|
.where(matches: { team_id: team_ids })
|
|
.group("matches.team_id")
|
|
.count
|
|
last_replay_at = Recording.ready.publicly_listed
|
|
.joins(stream_session: :match)
|
|
.where(matches: { team_id: team_ids })
|
|
.group("matches.team_id")
|
|
.maximum(:recorded_at)
|
|
last_live_at = StreamSession.broadcasting
|
|
.publicly_listed
|
|
.joins(:match)
|
|
.where(matches: { team_id: team_ids })
|
|
.group("matches.team_id")
|
|
.maximum(:started_at)
|
|
broadcasting_match_ids = StreamSession.broadcasting.select(:match_id)
|
|
upcoming_counts = Match.scheduled_for_live
|
|
.where(team_id: team_ids)
|
|
.where.not(id: broadcasting_match_ids)
|
|
.group(:team_id)
|
|
.count
|
|
|
|
teams.map do |team|
|
|
last_activity = [last_replay_at[team.id], last_live_at[team.id]].compact.max
|
|
Entry.new(
|
|
team: team,
|
|
live_now: live_set.include?(team.id),
|
|
replay_count: replay_counts[team.id].to_i,
|
|
upcoming_count: upcoming_counts[team.id].to_i,
|
|
last_activity_at: last_activity
|
|
)
|
|
end
|
|
end
|
|
|
|
def apply_toggle_filters(entries)
|
|
entries = entries.select(&:live_now) if @live
|
|
entries = entries.select { |entry| entry.replay_count.positive? } if @replays
|
|
entries
|
|
end
|
|
|
|
def sort_entries(entries)
|
|
entries.sort_by do |entry|
|
|
[
|
|
entry.live_now ? 0 : 1,
|
|
-(entry.last_activity_at&.to_i || 0),
|
|
entry.team.name.downcase
|
|
]
|
|
end
|
|
end
|
|
end
|
|
end
|