# frozen_string_literal: true

# NetworkRangesController - Browse and manage network ranges
#
# Provides interface for viewing, searching, and managing network ranges
# with their intelligence data and associated rules.
class NetworkRangesController < ApplicationController
  # Follow proper before_action order:
  # 1. Authentication/Authorization
  # All actions require authentication

  # 2. Resource loading
  before_action :set_network_range, only: [:show, :edit, :update, :destroy, :enrich]

  # GET /network_ranges
  def index
    @pagy, @network_ranges = pagy(policy_scope(NetworkRange.includes(:rules))
                               .order(updated_at: :desc))

    # Apply filters
    @network_ranges = apply_filters(@network_ranges)

    # Apply search
    if params[:search].present?
      @network_ranges = search_network_ranges(@network_ranges, params[:search])
    end

    # Statistics
    @total_ranges = NetworkRange.count
    @ranges_with_intelligence = NetworkRange.where.not(asn: nil).or(NetworkRange.where.not(company: nil)).count
    @datacenter_ranges = NetworkRange.where(is_datacenter: true).count
    @vpn_ranges = NetworkRange.where(is_vpn: true).count
    @proxy_ranges = NetworkRange.where(is_proxy: true).count

    # Top countries, companies, ASNs
    @top_countries = NetworkRange.where.not(country: nil).group(:country).count.sort_by { |_, c| -c }.first(10)
    @top_companies = NetworkRange.where.not(company: nil).group(:company).count.sort_by { |_, c| -c }.first(10)
    @top_asns = NetworkRange.where.not(asn: nil).group(:asn, :asn_org).count.sort_by { |_, c| -c }.first(10)
  end

  # GET /network_ranges/:id
  def show
    authorize @network_range
    @related_events = Event.joins("JOIN network_ranges ON events.ip_address <<= network_ranges.network")
                         .where("network_ranges.id = ?", @network_range.id)
                         .recent
                         .limit(100)

    @child_ranges = @network_range.child_ranges.limit(20)
    @parent_ranges = @network_range.parent_ranges.limit(10)
    @associated_rules = @network_range.rules.includes(:user).order(created_at: :desc)

    # Traffic analytics (if we have events)
    @traffic_stats = calculate_traffic_stats(@network_range)
  end

  # GET /network_ranges/new
  def new
    authorize NetworkRange
    @network_range = NetworkRange.new
  end

  # POST /network_ranges
  def create
    authorize NetworkRange
    @network_range = NetworkRange.new(network_range_params)
    @network_range.user = Current.user
    @network_range.source = 'user_created'

    respond_to do |format|
      if @network_range.save
        format.html { redirect_to @network_range, notice: 'Network range was successfully created.' }
        format.json { render json: @network_range.as_json(only: [:id, :network, :company, :asn, :asn_org, :country, :is_datacenter, :is_vpn, :is_proxy]) }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: { error: @network_range.errors.full_messages.join(', ') }, status: :unprocessable_entity }
      end
    end
  end

  # GET /network_ranges/:id/edit
  def edit
    authorize @network_range
  end

  # PATCH/PUT /network_ranges/:id
  def update
    authorize @network_range
    if @network_range.update(network_range_params)
      redirect_to @network_range, notice: 'Network range was successfully updated.'
    else
      render :edit, status: :unprocessable_entity
    end
  end

  # DELETE /network_ranges/:id
  def destroy
    authorize @network_range
    @network_range.destroy
    redirect_to network_ranges_url, notice: 'Network range was successfully deleted.'
  end

  # POST /network_ranges/:id/enrich
  def enrich
    authorize @network_range, :enrich?
    # Attempt to enrich this network range with API data
    # This would integrate with external IP intelligence services
    enrichment_service = NetworkEnrichmentService.new(@network_range)
    result = enrichment_service.enrich!

    if result[:success]
      redirect_to @network_range, notice: "Network range enriched with #{result[:fields_added]} new fields."
    else
      redirect_to @network_range, alert: "Failed to enrich network range: #{result[:error]}"
    end
  end

  # GET /network_ranges/lookup
  def lookup
    authorize NetworkRange, :lookup?
    ip_address = params[:ip]
    return render json: { error: 'IP address required' }, status: :bad_request if ip_address.blank?

    @ranges = NetworkRange.contains_ip(ip_address).includes(:rules)
    @ip_intelligence = IpRangeResolver.get_ip_intelligence(ip_address)
    @suggested_blocks = IpRangeResolver.suggest_blocking_ranges(ip_address)

    render :lookup
  end

  # GET /network_ranges/search
  def search
    authorize NetworkRange, :index?
    query = params[:q]

    if query.blank?
      render json: []
      return
    end

    # Search by network CIDR (cast inet to text for ILIKE), company, ASN org, or country
    @network_ranges = NetworkRange.where(
      "network::text ILIKE ? OR company ILIKE ? OR asn_org ILIKE ? OR country ILIKE ? OR asn::text ILIKE ?",
      "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%"
    ).limit(20)

    render json: @network_ranges.as_json(
      only: [:id, :network, :company, :asn, :asn_org, :country, :is_datacenter, :is_vpn, :is_proxy]
    )
  end

  private

  def set_network_range
    # Handle CIDR slugs (e.g., "40.77.167.100_32" -> "40.77.167.100/32")
    cidr = params[:id].gsub('_', '/')
    @network_range = NetworkRange.find_by!(network: cidr)
  end

  def network_range_params
    params.require(:network_range).permit(
      :network,
      :source,
      :creation_reason,
      :asn,
      :asn_org,
      :company,
      :country,
      :is_datacenter,
      :is_proxy,
      :is_vpn,
      :abuser_scores,
      :additional_data
    )
  end

  def apply_filters(scope)
    scope = scope.where(country: params[:country]) if params[:country].present?
    scope = scope.where(company: params[:company]) if params[:company].present?
    scope = scope.where(asn: params[:asn].to_i) if params[:asn].present?
    scope = scope.where(is_datacenter: true) if params[:datacenter] == 'true'
    scope = scope.where(is_vpn: true) if params[:vpn] == 'true'
    scope = scope.where(is_proxy: true) if params[:proxy] == 'true'
    scope = scope.where(source: params[:source]) if params[:source].present?
    scope
  end

  def search_network_ranges(scope, search_term)
    # Search by network CIDR, company, ASN, or country
    scope.where(
      "network ILIKE ? OR company ILIKE ? OR asn_org ILIKE ? OR country ILIKE ?",
      "%#{search_term}%", "%#{search_term}%", "%#{search_term}%", "%#{search_term}%"
    )
  end

  def calculate_traffic_stats(network_range)
    # Use the cached events_count for total requests (much more performant)
    # For detailed breakdown, we still need to query but we can optimize with a limit
    if network_range.events_count > 0
      events = Event.joins("JOIN network_ranges ON events.ip_address <<= network_ranges.network")
                    .where("network_ranges.id = ?", network_range.id)
                    .limit(1000) # Limit the sample for performance

      {
        total_requests: network_range.events_count, # Use cached count
        unique_ips: events.distinct.count(:ip_address),
        blocked_requests: events.blocked.count,
        allowed_requests: events.allowed.count,
        top_paths: events.group(:request_path).count.sort_by { |_, count| -count }.first(10),
        top_user_agents: events.group(:user_agent).count.sort_by { |_, count| -count }.first(5),
        recent_activity: events.recent.limit(20)
      }
    else
      # No events - return empty stats
      {
        total_requests: 0,
        unique_ips: 0,
        blocked_requests: 0,
        allowed_requests: 0,
        top_paths: {},
        top_user_agents: {},
        recent_activity: []
      }
    end
  end
end