# frozen_string_literal: true

require "test_helper"

class Api::EventsControllerTest < ActionDispatch::IntegrationTest
  def setup
    @dsn = Dsn.create!(name: "Test DSN", key: "test-api-key-1234567890abcdef")
    @disabled_dsn = Dsn.create!(name: "Disabled DSN", key: "disabled-key-1234567890abcdef", enabled: false)

    @sample_event_data = {
      "timestamp" => Time.current.iso8601,
      "method" => "GET",
      "path" => "/api/test",
      "status" => 200,
      "ip" => "192.168.1.100",
      "user_agent" => "TestAgent/1.0"
    }
  end

  test "should create event with valid DSN via query parameter" do
    post api_events_path,
         params: @sample_event_data.merge(baffle_key: @dsn.key),
         as: :json

    assert_response :success
    json_response = JSON.parse(response.body)
    assert json_response["success"]
    assert_not_nil json_response["rule_version"]
    assert_not_nil response.headers['X-Rule-Version']
  end

  test "should create event with valid DSN via Authorization header" do
    post api_events_path,
         headers: { "Authorization" => "Bearer #{@dsn.key}" },
         params: @sample_event_data,
         as: :json

    assert_response :success
    json_response = JSON.parse(response.body)
    assert json_response["success"]
  end

  test "should create event with valid DSN via X-Baffle-Auth header" do
    post api_events_path,
         headers: { "X-Baffle-Auth" => "Baffle baffle_key=#{@dsn.key}, baffle_version=1" },
         params: @sample_event_data,
         as: :json

    assert_response :success
    json_response = JSON.parse(response.body)
    assert json_response["success"]
  end

  test "should create event with valid DSN via Basic auth" do
    credentials = Base64.strict_encode64("#{@dsn.key}:password")
    post api_events_path,
         headers: { "Authorization" => "Basic #{credentials}" },
         params: @sample_event_data,
         as: :json

    assert_response :success
    json_response = JSON.parse(response.body)
    assert json_response["success"]
  end

  test "should create event with form encoded data" do
    post api_events_path,
         headers: { "Authorization" => "Bearer #{@dsn.key}" },
         params: @sample_event_data,
         as: :url_encoded

    assert_response :success
  end

  test "should include rules in response when agent has no version" do
    # Create some test rules
    Rule.create!(action: "block", pattern_type: "ip", pattern: "192.168.1.0/24", reason: "Test rule")
    Rule.create!(action: "allow", pattern_type: "ip", pattern: "10.0.0.0/8", reason: "Allow internal")

    post api_events_path,
         headers: { "Authorization" => "Bearer #{@dsn.key}" },
         params: @sample_event_data,
         as: :json

    assert_response :success
    json_response = JSON.parse(response.body)
    assert json_response["success"]
    assert json_response["rules_changed"]
    assert_not_nil json_response["rules"]
    assert_equal 2, json_response["rules"].length
  end

  test "should include only new rules when agent has old version" do
    # Create rules with different versions
    old_rule = Rule.create!(action: "block", pattern_type: "ip", pattern: "192.168.1.0/24", reason: "Old rule", version: 1)
    new_rule = Rule.create!(action: "block", pattern_type: "ip", pattern: "203.0.113.0/24", reason: "New rule", version: 2)

    event_data_with_version = @sample_event_data.merge("last_rule_sync" => 1)

    post api_events_path,
         headers: { "Authorization" => "Bearer #{@dsn.key}" },
         params: event_data_with_version,
         as: :json

    assert_response :success
    json_response = JSON.parse(response.body)
    assert json_response["success"]
    assert json_response["rules_changed"]
    assert_equal 1, json_response["rules"].length
    assert_equal "203.0.113.0/24", json_response["rules"].first["pattern"]
  end

  test "should not include rules when agent has latest version" do
    # Create a rule and get its version
    rule = Rule.create!(action: "block", pattern_type: "ip", pattern: "192.168.1.0/24", reason: "Test rule")
    latest_version = Rule.latest_version

    event_data_with_latest_version = @sample_event_data.merge("last_rule_sync" => latest_version)

    post api_events_path,
         headers: { "Authorization" => "Bearer #{@dsn.key}" },
         params: event_data_with_latest_version,
         as: :json

    assert_response :success
    json_response = JSON.parse(response.body)
    assert json_response["success"]
    assert_not json_response["rules_changed"]
    assert_nil json_response["rules"]
  end

  test "should return unauthorized with invalid DSN key" do
    post api_events_path,
         headers: { "Authorization" => "Bearer invalid-key-1234567890abcdef" },
         params: @sample_event_data,
         as: :json

    assert_response :unauthorized
  end

  test "should return unauthorized with disabled DSN" do
    post api_events_path,
         headers: { "Authorization" => "Bearer #{@disabled_dsn.key}" },
         params: @sample_event_data,
         as: :json

    assert_response :unauthorized
  end

  test "should return unauthorized with no authentication" do
    post api_events_path,
         params: @sample_event_data,
         as: :json

    assert_response :unauthorized
  end

  test "should return bad request with invalid JSON" do
    post api_events_path,
         headers: { "Authorization" => "Bearer #{@dsn.key}" },
         params: "invalid json {",
         as: :json

    assert_response :bad_request
  end

  test "should handle empty request body gracefully" do
    post api_events_path,
         headers: { "Authorization" => "Bearer #{@dsn.key}" },
         params: {},
         as: :json

    assert_response :success
    json_response = JSON.parse(response.body)
    assert json_response["success"]
  end

  test "should set sampling headers in response" do
    post api_events_path,
         headers: { "Authorization" => "Bearer #{@dsn.key}" },
         params: @sample_event_data,
         as: :json

    assert_response :success
    assert_not_nil response.headers['X-Sample-Rate']
    assert_not_nil response.headers['X-Sample-Until']
  end

  test "should set rule version header in response" do
    post api_events_path,
         headers: { "Authorization" => "Bearer #{@dsn.key}" },
         params: @sample_event_data,
         as: :json

    assert_response :success
    assert_not_nil response.headers['X-Rule-Version']
    assert_match /^\d+$/, response.headers['X-Rule-Version']
  end

  test "should handle large event payloads" do
    large_payload = @sample_event_data.merge(
      "large_field" => "x" * 10000, # 10KB of data
      "headers" => { "user-agent" => "TestAgent", "accept" => "*/*" },
      "custom_data" => Hash[*(1..100).map { |i| ["key#{i}", "value#{i}"] }.flatten]
    )

    post api_events_path,
         headers: { "Authorization" => "Bearer #{@dsn.key}" },
         params: large_payload,
         as: :json

    assert_response :success
  end

  test "should process event asynchronously" do
    # Clear any existing jobs
    ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true
    ActiveJob::Base.queue_adapter.perform_enqueued_jobs = false

    assert_difference 'ProcessWafEventJob.jobs.count', 1 do
      post api_events_path,
           headers: { "Authorization" => "Bearer #{@dsn.key}" },
           params: @sample_event_data,
           as: :json
    end

    assert_response :success
  end
end