# frozen_string_literal: true

require "test_helper"

class RuleTest < ActiveSupport::TestCase

  # Validation tests
  test "should create valid network rule" do
    network_range = NetworkRange.create!(cidr: "10.0.0.0/8")
    rule = Rule.new(
      waf_rule_type: "network",
      waf_action: "deny",
      network_range: network_range,
      source: "manual",
      user: users(:one)
    )
    assert rule.valid?
    rule.save!
    assert_equal 8, rule.priority # Auto-calculated from CIDR prefix
  end

  test "should create valid network rule with IPv6" do
    network_range = NetworkRange.create!(cidr: "2001:db8::/32")
    rule = Rule.new(
      waf_rule_type: "network",
      waf_action: "deny",
      network_range: network_range,
      source: "manual",
      user: users(:one)
    )
    assert rule.valid?
    rule.save!
    assert_equal 32, rule.priority
  end

  test "should create valid rate_limit rule" do
    rule = Rule.new(
      waf_rule_type: "rate_limit",
      waf_action: "deny",  # Rate limit rules use deny action when triggered
      conditions: { cidr: "0.0.0.0/0", scope: "global" },
      metadata: { limit: 100, window: 60 },
      source: "manual",
      user: users(:one)
    )
    assert rule.valid?
  end

  test "should create valid path_pattern rule" do
    rule = Rule.new(
      waf_rule_type: "path_pattern",
      waf_action: "log",
      conditions: { patterns: ["/.env", "/.git"] },
      source: "default",
      user: users(:one)
    )
    assert rule.valid?
  end

  test "should require waf_rule_type" do
    rule = Rule.new(waf_action: "deny", waf_rule_type: nil, conditions: { patterns: ["/test"] }, user: users(:one))
    assert_not rule.valid?
    assert_includes rule.errors[:waf_rule_type], "can't be blank"
  end

  test "should require waf_action" do
    rule = Rule.new(waf_rule_type: "path_pattern", waf_action: nil, conditions: { patterns: ["/test"] }, user: users(:one))
    assert_not rule.valid?
    assert_includes rule.errors[:waf_action], "can't be blank"
  end

  test "should validate network has valid CIDR" do
    rule = Rule.new(
      waf_rule_type: "network",
      waf_action: "deny",
      conditions: { cidr: "invalid-cidr" }, # Invalid CIDR
      user: users(:one)
    )
    assert_not rule.valid?
    # Network rules now validate differently - they need a network_range
    assert_includes rule.errors[:network_range], "is required for network rules"
  end

  test "should validate rate_limit has limit and window in metadata" do
    rule = Rule.new(
      waf_rule_type: "rate_limit",
      waf_action: "deny",  # Rate limit rules use deny action when triggered
      conditions: { cidr: "0.0.0.0/0", scope: "global" },
      metadata: { limit: 100 }, # Missing window
      user: users(:one)
    )
    assert_not rule.valid?
    assert_includes rule.errors[:metadata], "must include 'limit' and 'window' for rate_limit rules"
  end

  # Default value tests
  test "should default enabled to true" do
    network_range = NetworkRange.create!(cidr: "10.0.0.0/8")
    rule = Rule.create!(
      waf_rule_type: "network",
      waf_action: "deny",
      network_range: network_range,
      user: users(:one)
    )
    assert rule.enabled?
  end

  # Priority calculation tests
  test "should calculate priority from IPv4 CIDR prefix" do
    network_range = NetworkRange.create!(cidr: "192.168.1.0/24")
    rule = Rule.create!(
      waf_rule_type: "network",
      waf_action: "deny",
      network_range: network_range,
      user: users(:one)
    )
    assert_equal 24, rule.priority
  end

  # Scope tests
  test "active scope returns enabled and non-expired rules" do
    active_range = NetworkRange.create!(cidr: "10.0.0.0/8")
    active = Rule.create!(
      waf_rule_type: "network",
      waf_action: "deny",
      network_range: active_range,
      enabled: true,
      user: users(:one)
    )

    disabled_range = NetworkRange.create!(cidr: "192.168.0.0/16")
    disabled = Rule.create!(
      waf_rule_type: "network",
      waf_action: "deny",
      network_range: disabled_range,
      enabled: false,
      user: users(:one)
    )

    expired_range = NetworkRange.create!(cidr: "172.16.0.0/12")
    expired = Rule.create!(
      waf_rule_type: "network",
      waf_action: "deny",
      network_range: expired_range,
      enabled: true,
      expires_at: 1.hour.ago,
      user: users(:one)
    )

    results = Rule.active.to_a
    assert_includes results, active
    assert_not_includes results, disabled
    assert_not_includes results, expired
  end

  # Instance method tests
  test "active? returns true for enabled non-expired rule" do
    network_range = NetworkRange.create!(cidr: "10.0.0.0/8")
    rule = Rule.create!(
      waf_rule_type: "network",
      waf_action: "deny",
      network_range: network_range,
      enabled: true,
      user: users(:one)
    )
    assert rule.active?
  end

  test "disable! sets enabled to false and adds metadata" do
    network_range = NetworkRange.create!(cidr: "10.0.0.0/8")
    rule = Rule.create!(
      waf_rule_type: "network",
      waf_action: "deny",
      network_range: network_range,
      user: users(:one)
    )

    rule.disable!(reason: "False positive")

    assert_not rule.enabled?
    assert_equal "False positive", rule.metadata["disabled_reason"]
    assert rule.metadata["disabled_at"].present?
  end

  # Agent format tests
  test "to_agent_format returns correct structure" do
    network_range = NetworkRange.create!(cidr: "10.0.0.0/8")
    rule = Rule.create!(
      waf_rule_type: "network",
      waf_action: "deny",
      network_range: network_range,
      expires_at: 1.day.from_now,
      source: "manual",
      metadata: { reason: "Test" },
      user: users(:one)
    )

    format = rule.to_agent_format

    assert_equal rule.id, format[:id]
    assert_equal "network", format[:waf_rule_type]
    assert_equal "deny", format[:waf_action]
    assert_equal 8, format[:priority]
    assert_equal true, format[:enabled]
  end
end
