# frozen_string_literal: true

# ProcessWafPoliciesJob - Process firewall policies for a network range
#
# This job checks network ranges against active WAF policies and generates
# specific rules when matches are found.
class ProcessWafPoliciesJob < ApplicationJob
  queue_as :waf_policies

  retry_on StandardError, wait: 5.seconds, attempts: 3

  def perform(network_range:, event: nil)
    # network_range and event are passed as Global IDs and automatically deserialized
    return if network_range.nil?

    Rails.logger.debug "Processing WAF policies for network range #{network_range.cidr}"

    # Use WafPolicyMatcher to find and generate rules
    begin
      matcher = WafPolicyMatcher.new(network_range: network_range)
      result = matcher.match_and_generate_rules
    rescue => e
      Rails.logger.error "WafPolicyMatcher failed for network range #{network_range.cidr}: #{e.message}"
      result = { matching_policies: [], generated_rules: [] }
    end

    # Log results
    if result[:matching_policies].any?
      Rails.logger.info "Network range #{network_range.cidr} matched #{result[:matching_policies].length} policies"

      result[:matching_policies].each do |policy|
        Rails.logger.info "  - Matched policy: #{policy.name} (#{policy.policy_type}: #{policy.action})"
      end
    end

    if result[:generated_rules].any?
      Rails.logger.info "Generated #{result[:generated_rules].length} rules for network range #{network_range.cidr}"

      result[:generated_rules].each do |rule|
        Rails.logger.info "  - Rule: #{rule.waf_rule_type} #{rule.waf_action} for #{rule.network_range&.cidr} (ID: #{rule.id})"

        # Log if this is a redirect or challenge rule
        if rule.redirect_action?
          Rails.logger.info "    Redirect to: #{rule.redirect_url} (#{rule.redirect_status})"
        elsif rule.challenge_action?
          Rails.logger.info "    Challenge type: #{rule.challenge_type}"
        end
      end
    else
      Rails.logger.debug "No matching policies found for network range #{network_range.cidr}"
    end

    # Mark network range as evaluated
    network_range.update_column(:policies_evaluated_at, Time.current)

    # Update event record if provided
    if event.present?
      # Add policy match information to event metadata
      # Handle potential nil payload or type issues
      current_payload = event.payload || {}

      # Ensure payload is a hash before merging
      unless current_payload.is_a?(Hash)
        Rails.logger.warn "Event #{event.id} has invalid payload type: #{current_payload.class}, resetting to hash"
        current_payload = {}
      end

      event.update!(payload: current_payload.merge({
        policy_matches: {
          matching_policies_count: result[:matching_policies].length,
          generated_rules_count: result[:generated_rules].length,
          processed_at: Time.current.iso8601
        }
      }))
    end
  end

  # Class method for batch processing multiple network ranges
  def self.process_network_ranges(network_range_ids)
    network_range_ids.each do |network_range_id|
      network_range = NetworkRange.find_by(id: network_range_id)
      perform_later(network_range: network_range) if network_range
    end
  end

  # Class method to reprocess all network ranges for a specific policy
  def self.reprocess_for_policy(waf_policy)
    waf_policy_id = waf_policy.is_a?(WafPolicy) ? waf_policy.id : waf_policy

    # Find all network ranges that could match this policy type
    network_ranges = case waf_policy.policy_type
                    when 'country'
                      NetworkRange.where.not(country: nil)
                    when 'asn'
                      NetworkRange.where.not(asn: nil)
                    when 'company'
                      NetworkRange.where.not(company: nil)
                    when 'network_type'
                      NetworkRange.where("is_datacenter = ? OR is_proxy = ? OR is_vpn = ?", true, true, true)
                    else
                      NetworkRange.none
                    end

    Rails.logger.info "Reprocessing #{network_ranges.count} network ranges for policy #{waf_policy_id}"

    network_ranges.find_each do |network_range|
      perform_later(network_range: network_range)
    end
  end
end