class LoggingController < ApplicationController
  include ChangeNetwork
  include CacheExistence
  before_filter :authenticate_user!
  before_filter :dashboard_topbar
  load_and_authorize_resource :class => Logging,:except => [:showing_tag,:change_network,:event_logging, :filter_event_logging]
  load_and_authorize_resource :class => EventLogging,:only => [:event_logging]
  skip_load_resource :only => [:create,:update,:event_logging, :change_network]
  check_policy_for :create, :update, :destroy, with: Logging, id_param: :id

  def index
    unless @current_network.blank?
      @aps_collection = []
      if params[:id].blank?
        @logging = @current_network.loggings.new
      else
         @logging = @current_network.loggings.find_by_id(params[:id])
         @aps_collection = @current_network.grouped_collection_of_ap_and_tags
      end
      @loggings = Logging.where(:location_network_id => @current_network.id)
      @event_enabled = @loggings.where(:location_network_id => @current_network.id,logging_type: 'event_logging').present? ? 1 : 0
    end
  end

  def create
    @logging = @current_network.loggings.new(logging_params)
    respond_to do |format|
      if @logging.save
        flash[:success] = "Successfully created Logging details"
        format.json { render action: 'create', status: :created, location: @logging}
        format.html { redirect_to logging_index_path}
      else
        flash[:error] = "Oops! there was some problem in creating Logging details"
        format.html { render action: 'new' }
        format.json { render json: @logging.errors, status: :unprocessable_entity }
      end
    end
    # redirect_to logging_index_path
  end

  def update
    @logging = @current_network.loggings.find_by_id(params[:id])
    respond_to do |format|
      if @logging.update(logging_params)
        flash[:success] = "Successfully updated Logging details"
        format.json        
        format.html { redirect_to logging_index_path }
      else
        flash[:error] = "Oops! there was some problem in updating Logging details"
        format.html { render action: 'edit' }
        format.json { render json: @logging.errors, status: :unprocessable_entity }
      end
    end
  end

  def showing_tag
    @ris = RouterInventory.get_all_based_on_tag(params[:id])
  end

  def updatus_enabled_status
     render :json=> {:status=>false,:reload => false}.to_json and return if params[:id].blank?
     logging =  @current_network.loggings.find_by_id(params[:id])
    render :json=> {:status=>'notice',:msg=>"Oops! Requested Logging not found since the network got changed so page will be refreshed in 5 seconds",:reload => true,:id => "#{@current_network.id}"}.to_json and return if logging.blank?
    value = params[:is_enabled] == 'true' ? 1 : 0
    if logging.update_attributes({:is_enabled => value })
      render :json=> {:status=>'success',:msg=>'Successfully updated Logging',:reload => false}.to_json and return
    else
      render :json=> {:status=>'error',:msg=>'Oops! Problem updating Logging Please try after some time',:reload => false}.to_json and return
    end
  end

  def get_selected_associated_resources
    resources = @current_network.loggings.where.not(:id => params[:logging_id]).where(logging_type: params[:type]).map(&:associated_resources)
    resources = resources.flatten
     hash = {}
    tag = []
    hash["Router_Inventory"] = []
    hash["Tags"] = []
      ln = @current_network
      hash["Network"] = [[ln.network_name, "network:#{ln.id}"]] if !resources.include? "network:#{ln.id}"
      current_user.router_inventories_full.where(location_network_id: ln.id).each do |ri|
        if  !resources.include? "AP:#{ri.id}"
         hash["Router_Inventory"] << ["#{ri.name.present? ? (ri.name + " (#{ri.mac_id.last(8)})") : ri.mac_id}", "AP:#{ri.id}"]
        end
      end

      current_user.router_inventories_full.where(location_network_id: ln.id).each do |ri|
        ri.tags.each do |l|
          if  !resources.include? "tag:#{ri.id}"
            tag << [l.name, "tag:#{l.id}"]
          end
        end
      end
      hash["Tags"] = tag.uniq
      resource_hash = ''
      hash.each do |h|
        resource_hash += '<optgroup label=' + h[0].to_s + '>'
        h[1].each do |v|
          if resources.include? v[1]
            resource_hash += '<option value=' + v[1].to_s + ' selected=selected>' + v[0] +'</option></optgroup>'
          else
            resource_hash += '<option value=' + v[1].to_s + '>' + v[0] +'</option></optgroup>'
          end
        end
      end
    render :json=> {:data => resource_hash}
  end

  def event_logging
    unless @current_network.blank?
      @event_logging = EventLogging.new
      @mac_ids = @current_network.router_inventories.map {|ri| ["#{ri.name.present? ? (ri.name + " (#{ri.mac_id.last(8)})") : ri.mac_id}", "#{ri.mac_id}"]}
      @event_loggings = EventLogging.where(:location_network_id => @current_network.id)
    end
  end

  def change_network
    change_user_network
  end

  def filter_event_logging
    zone_tz = @current_network.get_timezone || 'UTC'

    from_date = params[:date].to_s.split('-')[0].presence
    to_date   = params[:date].to_s.split('-')[1].presence

    s_h = from_date ? ActiveSupport::TimeZone.new(zone_tz).parse(from_date.to_s).utc : nil
    e_h = to_date ? ActiveSupport::TimeZone.new(zone_tz).parse(to_date.to_s).end_of_day.utc : nil

    query = {}
    if s_h && e_h
      query[:timestamp] = { '$gte' => s_h, '$lt' => e_h }
    elsif s_h
      query[:timestamp] = { '$gte' => s_h, '$lt' => s_h + 1.day }
    end

    query[:type_id] = { '$in' => params[:type_id].split(',').map(&:to_i) } if params[:type_id].present?
    query[:category_id] = { '$in' => params[:category].split(',').map(&:to_i) } if params[:category].present?
    query[:mac_id] = { '$in' => params[:mac].split(',') } if params[:mac].present?
    
    if params[:network_id].present?
      requested_location_id = params[:network_id].to_i
      
      location_network = if current_user.is_user_allowed_all_networks?
        LocationNetwork.find_by(id: requested_location_id)
      else
        current_user.get_all_permitted_networks_for_non_admin.where(id: requested_location_id).first
      end
      
      unless location_network
        return render json: { error: "Location network not found " }, status: :forbidden
      end

      query[:location_network_id] = requested_location_id
      
    elsif params[:org_id] == '1'
      query[:location_network_id] = { '$in' => current_user.location_networks.pluck(:id) }
    else
      query[:location_network_id] = @current_network.id
    end

    respond_to do |format|
      format.json do
        @network = @current_network
        
        page = (params[:page] || 1).to_i
        per_page = (params[:per_page] || 100).to_i
        per_page = [per_page, 1000].min  
        
        # Calculate offset
        offset = (page - 1) * per_page
        
        # Get total count for pagination metadata
        total_count = EventLogging.where(query).count
        total_pages = (total_count.to_f / per_page).ceil
        
        # Fetch paginated records
        @event_loggings = EventLogging.where(query)
                                      .order(timestamp: :desc)
                                      .skip(offset)

        current_page_count = @event_loggings.count   
        previous_page = page > 1 ? page - 1 : nil
        next_page = page < total_pages ? page + 1 : nil                          
                                                                       
        network_timezone = @current_network.get_timezone || 'UTC'
        events = @event_loggings.map do |event|
          formatted_timestamp = event.timestamp.in_time_zone(network_timezone).strftime('%d-%m-%Y %H:%M:%S %Z')
          {
            mac_id: event.mac_id,
            client_mac: event.client_mac,
            category_id: event.category_id,
            description: event.description,
            type_id: event.type_id,
            timestamp: formatted_timestamp,
            unix_timestamp: event.timestamp.to_i
          }
        end
        
        render json: {
          events: events,
          meta: {
            per_page: per_page,
            count: current_page_count,
            current: page,
            previous: previous_page,
            next: next_page,
            pages: total_pages,
            total: total_count
          }
        }
      end
      
      format.csv do
        headers['Content-Disposition'] = "attachment; filename=\"event_loggings_#{Time.now.to_i}.csv\""
        headers['Content-Type'] ||= 'text/csv'
        headers['X-Accel-Buffering'] = 'no'
        headers['Cache-Control'] = 'no-cache'
        self.response_body = Enumerator.new do |yielder|
          yielder << "Timestamp,Device,Category,Client MAC,Type,Description\n"
          network_timezone = @current_network.get_timezone || 'UTC'
          # Stream directly from the MongoDB 
          EventLogging.collection.find(query).sort(timestamp: -1).batch_size(500).each do |doc|
            category_id = doc['category_id'].to_s
            type_id = doc['type_id'].to_s
            category_name = EventLogging::EVENT_CATEGORY[category_id] rescue nil
            type_name = EventLogging::EVENT_CATEGORY_MAP[category_id][type_id] rescue nil
            
            # timestamp to network timezone
            timestamp = doc['timestamp']
            formatted_timestamp = timestamp.in_time_zone(network_timezone).strftime('%d-%m-%Y %H:%M:%S %Z')
            
            client_mac = doc['client_mac'].present? ? doc['client_mac'] : '-'
            
            row = [
              formatted_timestamp,
              doc['mac_id'],
              category_name,
              client_mac,
              type_name,
              doc['description']
            ].map { |v| "\"#{v}\"" }.join(',')
            yielder << row + "\n"
          end
        end
      end
    end
  end

 
  def destroy
    @logging = @current_network.loggings.find_by_id(params[:id])
    unless @logging.blank?
      if @logging.destroy
        flash[:success] = "Successfully deleted Logging details #{@logging.name}"
      else
        flash[:notice] = "Oops! there was some problem in deleting Logging details"
        Rails.logger.warn "#{@logging.errors.full_messages}"
      end
    else
       flash[:warning] = "Oops! Logging details not found"
    end
    respond_to do |format|
      format.json
      format.html { redirect_to logging_index_path }
    end
  end

  private

  def current_ability
    if cache_exist?
      @current_ability ||= Ability::LoggingAbility.new(current_user)
    else
      @current_ability ||= Ability.new(current_user)
    end
  end

  def logging_params
    params.require(:logging).permit(:name,:is_enabled,:logging_type,:upload_type,:location_network_id, :associated_resources => [],:extra_data => [:uploaded_user,:upload_url,:upload_password,:ip_address,:port,:username,:password])
  end

end
