# frozen_string_literal: true

require 'net/http'
require 'json'
require 'uri'

module PulseRadar
  class Client
    DEFAULT_ENDPOINT = 'https://ingest.pulseradar.cloud/v1/logs'
    FLUSH_SIZE = 50
    FLUSH_INTERVAL = 5 # seconds

    def initialize(api_key:, source: 'ruby', server_id: nil, endpoint: nil, async: true)
      @api_key = api_key
      @source = source
      @server_id = server_id
      @endpoint = endpoint || DEFAULT_ENDPOINT
      @async = async
      @queue = []
      @mutex = Mutex.new
      @uri = URI.parse(@endpoint)

      start_flush_timer if @async
      at_exit { flush }
    end

    def debug(message, **fields)   = log('debug', message, fields)
    def info(message, **fields)    = log('info', message, fields)
    def warning(message, **fields) = log('warning', message, fields)
    def error(message, **fields)   = log('error', message, fields)
    def critical(message, **fields)= log('critical', message, fields)

    def capture_exception(exception = nil, **fields)
      exc = exception || $!
      return unless exc

      frames = (exc.backtrace || []).first(5).join(' | ')
      error(
        "#{exc.class}: #{exc.message}",
        exception_type: exc.class.to_s,
        stack: frames,
        **fields
      )
    end

    def flush
      batch = nil
      @mutex.synchronize do
        batch = @queue.dup
        @queue.clear
      end
      send_batch(batch) if batch && !batch.empty?
    end

    private

    def log(level, message, fields)
      entry = {
        level: level,
        message: message.to_s,
        source: @source,
        timestamp: Time.now.utc.strftime('%Y-%m-%dT%H:%M:%S.%LZ'),
        fields: fields.transform_keys(&:to_s).transform_values(&:to_s)
      }

      if @async
        @mutex.synchronize { @queue << entry }
        flush if @queue.size >= FLUSH_SIZE
      else
        send_batch([entry])
      end
    end

    def send_batch(entries)
      Thread.new do
        begin
          http = Net::HTTP.new(@uri.host, @uri.port)
          http.use_ssl = @uri.scheme == 'https'
          http.open_timeout = 5
          http.read_timeout = 10

          request = Net::HTTP::Post.new(@uri.request_uri)
          request['Content-Type'] = 'application/json'
          request['Authorization'] = "Bearer #{@api_key}"
          request['User-Agent'] = 'pulseradar-ruby/1.0'
          request['X-Server-Id'] = @server_id if @server_id
          request.body = JSON.generate(entries)

          http.request(request)
        rescue StandardError => e
          $stderr.puts "[pulseradar] send error: #{e.message}"
        end
      end
    end

    def start_flush_timer
      Thread.new do
        loop do
          sleep FLUSH_INTERVAL
          flush
        end
      end
    end
  end
end
