# frozen_string_literal: true

require 'travis/cli'
require 'travis/tools/notification'

module Travis
  module CLI
    class Monitor < ApiCommand
      description "live monitor for what's going on"
      on('-m', '--my-repos', 'Only monitor my own repositories')

      on('-r', '--repo SLUG', 'monitor given repository (can be used more than once)') do |c, slug|
        c.repos << slug
        c.send(:error, 'SLUG should be of the form OWNER/REPO') unless slug.split('/').compact.size == 2
      end

      types = Tools::Notification::DEFAULT.map(&:to_s).join(', ')
      on('-n', '--[no-]notify [TYPE]', "send out desktop notifications (optional type: #{types})") do |c, type|
        c.setup_notification(type)
      end

      on('-b', '--builds', 'only monitor builds, not jobs')
      on('-p', '--push', 'monitor push events')
      on('-P', '--pull', 'monitor pull request events')

      attr_reader :repos, :notification

      def initialize(*)
        @repos = []
        super
      end

      def setup
        super
        repos.map! { |r| repo(r) }
        repos.concat(user.repositories) if my_repos?
        setup_notification(true) unless notification
        debug "Using notifications: #{notification.class.name[/[^:]+$/]}"
      end

      def setup_notification(type = nil)
        refuse = false
        case type
        when false     then @notification = Tools::Notification.new(:dummy)
        when nil, true then @notification = Tools::Notification.new
        else
          refuse        = true
          @notification = Tools::Notification.new(type)
        end
      rescue ArgumentError => e
        @notification = Tools::Notification.new(:dummy)
        error(e.message) if refuse
        warn(e.message)
      end

      def description
        case repos.size
        when 0 then session.config['host']
        when 1 then repos.first.slug
        else "#{repos.size} repositories"
        end
      end

      def events
        events = %w[build:started build:finished]
        events << 'job:started' << 'job:finished' unless builds?
        events
      end

      def all?
        !pull? and !push?
      end

      def monitor?(entity)
        return true if all?

        entity.pull_request? ? pull? : push?
      end

      def display(entity, time)
        say [
          color(formatter.time(time), entity.color),
          color(entity.inspect_info, [entity.color, :bold]),
          color(entity.state, entity.color),
          color(entity.commit.subject, entity.color)
        ].join(' ')
        notification.notify(entity.repository.slug, [
          entity.class.name[/[^:]+$/],
          entity.number,
          "#{entity.state}:",
          entity.commit.subject
        ].join(' '))
      end

      def handle_event(event)
        entity = event.job          || event.build
        time   = entity.finished_at || entity.started_at
        display(entity, time) if monitor? entity
      rescue Travis::Client::Error => e
        raise e if explode?
      end

      def run
        listen(*repos) do |listener|
          listener.on_connect { say description, "Monitoring #{'builds for ' if builds?}%s:" }
          listener.on(*events) { |e| handle_event(e) }
        end
      end
    end
  end
end
