# frozen_string_literal: true

require 'English'
require 'riemann/tools'

module Riemann
  module Tools
    class Freeswitch
      include Riemann::Tools

      opt :calls_warning, 'Calls warning threshold', default: 100
      opt :calls_critical, 'Calls critical threshold', default: 300
      opt :pid_file, 'FreeSWITCH daemon pidfile', type: String, default: '/var/run/freeswitch/freeswitch.pid'

      def initialize
        super

        @limits = {
          calls: { critical: opts[:calls_critical], warning: opts[:calls_warning] },
        }
      end

      def dead_proc?(pid)
        Process.getpgid(pid)
        false
      rescue Errno::ESRCH
        true
      end

      def alert(service, state, metric, description)
        report(
          service: service.to_s,
          state: state.to_s,
          metric: metric.to_f,
          description: description,
        )
      end

      def exec_with_timeout(cmd, timeout)
        pid = Process.spawn(cmd, { %i[err out] => :close, :pgroup => true })
        begin
          Timeout.timeout(timeout) do
            Process.waitpid(pid, 0)
            $CHILD_STATUS.exitstatus.zero?
          end
        rescue Timeout::Error
          Process.kill(15, -Process.getpgid(pid))
          puts "Killed pid: #{pid}"
          false
        end
      end

      def tick
        # Determine how many current calls I have according to FreeSWITCH
        fs_calls = `fs_cli -x "show calls count"| grep -Po '^\\d+'`.to_i

        # Determine how many current channels I have according to FreeSWITCH
        fs_channels = `fs_cli -x "show channels count"| grep -Po '^\\d+'`.to_i

        # Determine how many conferences I have according to FreeSWITCH
        fs_conferences = `fs_cli -x "conference list"| grep -Pco '^Conference'`.to_i

        # Try to read pidfile. If it fails use Devil's dummy PID
        begin
          fs_pid = File.read(opts[:pid_file]).to_i
        rescue StandardError
          puts "Couldn't read pidfile: #{opts[:pid_file]}"
          fs_pid = -666
        end

        fs_threads = fs_pid.positive? ? `ps huH p #{fs_pid} | wc -l`.to_i : 0

        # Submit calls to riemann
        if fs_calls > @limits[:calls][:critical]
          alert 'FreeSWITCH current calls', :critical, fs_calls, "Number of calls are #{fs_calls}"
        elsif fs_calls > @limits[:calls][:warning]
          alert 'FreeSWITCH current calls', :warning, fs_calls, "Number of calls are #{fs_calls}"
        else
          alert 'FreeSWITCH current calls', :ok, fs_calls, "Number of calls are #{fs_calls}"
        end

        # Submit channels to riemann
        if fs_channels > @limits[:calls][:critical]
          alert 'FreeSWITCH current channels', :critical, fs_channels, "Number of channels are #{fs_channels}"
        elsif fs_channels > @limits[:calls][:warning]
          alert 'FreeSWITCH current channels', :warning, fs_channels, "Number of channels are #{fs_channels}"
        else
          alert 'FreeSWITCH current channels', :ok, fs_channels, "Number of channels are #{fs_channels}"
        end

        # Submit conferences to riemann
        if fs_conferences > @limits[:calls][:critical]
          alert 'FreeSWITCH current conferences', :critical, fs_conferences,
                "Number of conferences are #{fs_conferences}"
        elsif fs_conferences > @limits[:calls][:warning]
          alert 'FreeSWITCH current conferences', :warning, fs_conferences,
                "Number of conferences are #{fs_conferences}"
        else
          alert 'FreeSWITCH current conferences', :ok, fs_conferences, "Number of conferences are #{fs_conferences}"
        end

        # Submit threads to riemann
        alert 'FreeSWITCH current threads', :ok, fs_threads, "Number of threads are #{fs_threads}" if fs_threads

        # Submit status to riemann
        if dead_proc?(fs_pid)
          alert 'FreeSWITCH status', :critical, -1, 'FreeSWITCH service status: not running'
        else
          alert 'FreeSWITCH status', :ok, nil, 'FreeSWITCH service status: running'
        end

        # Submit CLI status to riemann using timeout in case it's unresponsive
        if exec_with_timeout('fs_cli -x status', 2)
          alert 'FreeSWITCH CLI status', :ok, nil, 'FreeSWITCH CLI status: responsive'
        else
          alert 'FreeSWITCH CLI status', :critical, -1, 'FreeSWITCH CLI status: not responding'
        end
      end
    end
  end
end