# frozen_string_literal: true

require "test_helper"

module Api
  class RulesControllerTest < ActionDispatch::IntegrationTest
    setup do
      @dsn = Dsn.create!(
        name: "Test DSN",
        key: "test-key-#{SecureRandom.hex(8)}"
      )

      @rule1 = Rule.create!(
        rule_type: "network_v4",
        action: "deny",
        conditions: { cidr: "10.0.0.0/8" },
        source: "manual"
      )

      @rule2 = Rule.create!(
        rule_type: "rate_limit",
        action: "rate_limit",
        conditions: { cidr: "0.0.0.0/0", scope: "global" },
        metadata: { limit: 100, window: 60 }
      )
    end

    test "version endpoint returns correct structure" do
      get "/api/rules/version", headers: { "Authorization" => "Bearer #{@dsn.key}" }

      assert_response :success

      json = JSON.parse(response.body)
      assert json["version"].present?
      assert_equal 2, json["count"]
      assert json["sampling"].present?
      assert json["sampling"]["allowed_requests"].present?
      assert json["sampling"]["blocked_requests"].present?
      assert json["sampling"]["load_level"].present?
    end

    test "version endpoint requires valid project key" do
      get "/api/invalid-key/rules/version"

      assert_response :unauthorized
      json = JSON.parse(response.body)
      assert_equal "Invalid DSN key", json["error"]
    end

    test "version endpoint rejects disabled projects" do
      @dsn.update!(enabled: false)

      get "/api/rules/version"

      assert_response :forbidden
      json = JSON.parse(response.body)
      assert_equal "DSN is disabled", json["error"]
    end

    test "index endpoint returns all active rules" do
      get "/api/rules"

      assert_response :success

      json = JSON.parse(response.body)
      assert json["version"].present?
      assert json["sampling"].present?
      assert_equal 2, json["rules"].length

      rule = json["rules"].find { |r| r["id"] == @rule1.id }
      assert_equal "network_v4", rule["rule_type"]
      assert_equal "deny", rule["action"]
      assert_equal({ "cidr" => "10.0.0.0/8" }, rule["conditions"])
      assert_equal 8, rule["priority"]
    end

    test "index endpoint excludes disabled rules" do
      @rule1.update!(enabled: false)

      get "/api/rules"

      assert_response :success

      json = JSON.parse(response.body)
      assert_equal 1, json["rules"].length
      assert_equal @rule2.id, json["rules"].first["id"]
    end

    test "index endpoint excludes expired rules" do
      @rule1.update!(expires_at: 1.hour.ago)

      get "/api/rules"

      assert_response :success

      json = JSON.parse(response.body)
      assert_equal 1, json["rules"].length
      assert_equal @rule2.id, json["rules"].first["id"]
    end

    test "index endpoint with since parameter returns recent rules" do
      # Update rule1 to be older
      @rule1.update_column(:updated_at, 2.hours.ago)

      since_time = 1.hour.ago.iso8601
      get "/api/rules?since=#{since_time}"

      assert_response :success

      json = JSON.parse(response.body)
      assert_equal 1, json["rules"].length
      assert_equal @rule2.id, json["rules"].first["id"]
    end

    test "index endpoint with since parameter includes disabled rules" do
      @rule1.update!(enabled: false) # This updates updated_at

      since_time = 1.minute.ago.iso8601
      get "/api/rules?since=#{since_time}"

      assert_response :success

      json = JSON.parse(response.body)

      # Should include the disabled rule for agent to remove it
      disabled_rule = json["rules"].find { |r| r["id"] == @rule1.id }
      assert disabled_rule.present?
      assert_equal false, disabled_rule["enabled"]
    end

    test "index endpoint with invalid timestamp returns error" do
      get "/api/rules?since=invalid-timestamp"

      assert_response :bad_request
      json = JSON.parse(response.body)
      assert json["error"].include?("Invalid timestamp format")
    end

    test "index endpoint requires authentication" do
      get "/api/invalid-key/rules"

      assert_response :unauthorized
    end

    test "index endpoint includes sampling information" do
      get "/api/rules"

      assert_response :success

      json = JSON.parse(response.body)
      sampling = json["sampling"]

      assert_equal 1.0, sampling["allowed_requests"]
      assert_equal 1.0, sampling["blocked_requests"]
      assert_equal 1.0, sampling["rate_limited_requests"]
      assert sampling["effective_until"].present?
      assert_equal "normal", sampling["load_level"]
    end

    test "rules are ordered by updated_at for sync" do
      # Create rules with different timestamps
      oldest = Rule.create!(
        rule_type: "network_v4",
        action: "deny",
        conditions: { cidr: "192.168.1.0/24" }
      )
      oldest.update_column(:updated_at, 3.hours.ago)

      middle = Rule.create!(
        rule_type: "network_v4",
        action: "deny",
        conditions: { cidr: "192.168.2.0/24" }
      )
      middle.update_column(:updated_at, 2.hours.ago)

      newest = Rule.create!(
        rule_type: "network_v4",
        action: "deny",
        conditions: { cidr: "192.168.3.0/24" }
      )

      get "/api/rules?since=#{4.hours.ago.iso8601}"

      assert_response :success

      json = JSON.parse(response.body)
      ids = json["rules"].map { |r| r["id"] }

      # Should be ordered oldest to newest by updated_at
      assert_equal [oldest.id, middle.id], ids.first(2)
      assert_equal newest.id, ids.last
    end
  end
end
