class UpgradesController < ApplicationController
  include CacheExistence
  before_filter :authenticate_user!
  before_action :set_upgrade, only: [:show, :edit, :update, :destroy]
  load_and_authorize_resource :class => Upgrade
  skip_load_resource :only => [:new, :create, :upgrade_list]

  # GET /upgrades
  # GET /upgrades.json
  def index
    if params[:id].blank?
      @upgrade = Upgrade.new(:upgrade_type => "automatic", :schedule_type => "now")
      @ar = []
    else
      @upgrade = Upgrade.find(params[:id])
      #@ar = SnmpConfig.tagging_lists(@upgrade.aps)
    end
    if session[:assumes_upgrade_version] == true || current_user.is_super_admin == true
      @upgrade_datas = UpgradeData.where(organisation_id: [nil, current_user.organisation_id]) 
    else
      @upgrade_datas = UpgradeData.where(organisation_id: [nil, current_user.organisation_id],:is_released=> true)
    end  
    @upgrades = current_user.organisation.upgrades.includes(:router_inventories) rescue []
    if request.format.json?
      render json: {data: {upgrades: @upgrades.map(&:json_build)}}
    end
  end

  # GET /upgrades/1
  # GET /upgrades/1.json
  def show
    if request.format.json?
      render json: {data: {upgrades: @upgrade.json_build}}
    end
  end

  # GET /upgrades/new
  def new
    @upgrade = Upgrade.new
  end

  # GET /upgrades/1/edit
  def edit
  end

  # POST /upgrades
  # POST /upgrades.json
   def create
    create_update(upgrade_params)
    # AclInventory.save_avl_inventories(params[:aps_inventory_tags],@portforwarding_group,current_user.organisation,"pf_group")
    if request.format.json?
      render json: @json_data, status: @json_data[:status]
    else
      redirect_to :action=>:index
    end
  end

  def create_update(upgrade)
    if UpgradeData.last.blank?
      flash[:error] = "No New Firware upgrade found"
      @json_data = {message: "No New Firware upgrade found", status: 422}
    else
      @no_upgrade_aps = []
      inventory_list = Set.new
      upgrade[:version] = UpgradeData.last.try(:version) unless upgrade[:upgrade_type] == 'manual'
      @upgrade_data = UpgradeData.where(version: upgrade[:version]).last
        upgrade[:aps].each do |router|
        id = router.split(":")
        inventory_list << RouterInventory.find_by_id(id[1].to_i) if id[0].eql?"AP"
        inventory_list += LocationNetwork.where(:id => id[1]).first.try(:router_inventories) if id[0].eql?"network"
        inventory_list  += RouterInventory.tagged_with(ActsAsTaggableOn::Tag.find(id[1])) if id[0].eql?"tag"
      end
      do_upgrade(inventory_list,upgrade)
      #@upgrade_not_available = HardwarePart.where("part_number not in (?)", upgrade_data.url.keys).pluck :name
      if @no_upgrade_aps.present?
        flash[:error] = "#{upgrade[:version]} version upgrade is not available for these devices #{@no_upgrade_aps.join(', ')}." || ""  #|| @upgrade_not_available.present?
        @json_data = {message: "#{upgrade[:version]} version upgrade is not available for these devices #{@no_upgrade_aps.join(', ')}.", status: 422}
      else
        flash[:success] = @msg
      end
    end
  end


  def do_upgrade(inventory_list,upgrade)
    (inventory_list || []).each do |x|
      ri = RouterInventory.find_by_id(x.id.to_i)
      next if ri.blank?
      part_number = ri.hardware_part.try(:part_number)
      unless @upgrade_data && @upgrade_data.url[part_number]
        @no_upgrade_aps << ri.mac_id
        next if true
        #return if true
      end
      router = 'AP:' + x.id.to_s
      if ri.pending_upgrade.nil? and params[:id].blank?
        ri.create_pending_upgrade({:version => upgrade[:version], :aps => router, :organisation_id => ri.organisation_id, :upgrade_type => upgrade[:upgrade_type], :schedule_type => upgrade[:schedule_type], :schedule_at => upgrade[:schedule_at], :time_zone => upgrade[:time_zone], :save_prev_config => upgrade[:save_prev_config]})
        @msg = "Successfully created Upgrade!"
        @json_data = {message: "Successfully created Upgrade!", status: 200}
      else
        exis_upgrade = ri.pending_upgrade
        exis_upgrade.update_attributes({:version=>upgrade[:version], :aps => router, :router_inventory_id => x.id, :organisation_id => ri.organisation_id,:upgrade_type => upgrade[:upgrade_type], :schedule_type => upgrade[:schedule_type], :schedule_at => upgrade[:schedule_at], :time_zone => upgrade[:time_zone], :save_prev_config => upgrade[:save_prev_config]})
        @msg = "Successfully updated Upgrade!"
        @json_data = {message: "Successfully updated Upgrade!", status: 200}
      end
    end
  end

  # PATCH/PUT /upgrades/1
  # PATCH/PUT /upgrades/1.json
  def update
    create_update(upgrade_params)
    if request.format.json?
      render json: @json_data, status: @json_data[:status]
    else
      redirect_to :action=>:index
    end
  end

  # DELETE /upgrades/1
  # DELETE /upgrades/1.json
  def destroy
    if @upgrade.pending?
     if @upgrade.destroy
        flash[:success] = "Successfully deleted upgrade"
        json_data = {data: {}, status: 200}
     else
        flash[:notice] = "Oops! there was some problem in deleting upgrade"
        json_data = {message: "Oops! there was some problem in deleting upgrade", status: 422}
        Rails.logger.warn "#{@upgrade.errors.full_messages}"
     end
    else
      flash[:warning] = "Oops! The selected upgrade not available to be deleted"
      json_data = {message: "Oops! The selected upgrade not available to be deleted", status: 422}
    end
    if request.format.json?
      render json: json_data, status: json_data[:status]
    else
      redirect_to :action=>:index
    end
  end

  def upgrade_list
    begin
      # Start with a relation, do not eager load yet
      upgrades = current_user.current_network.organisation.upgrades
      
      search_value = params[:search].is_a?(Hash) ? params[:search][:value].presence : params[:search].presence


      if search_value.present?
        search_term = "%#{search_value}%"
        upgrades = upgrades.joins(:router_inventory)
        where_clause = "upgrades.version LIKE :q OR upgrades.aps LIKE :q OR " +
       "CONCAT(DATE_FORMAT(CONVERT_TZ(COALESCE(upgrades.schedule_at, upgrades.created_at), '+00:00', '+00:00'), '%d %M %Y - %H:%i'), ' (', COALESCE(upgrades.time_zone, 'UTC'), ')') LIKE :q OR " +
        "CONCAT(DATE_FORMAT(CONVERT_TZ(upgrades.created_at, '+00:00', '+00:00'), '%d %M %Y - %H:%i'), ' UTC') LIKE :q OR " +
        "COALESCE(upgrades.status, 'Pending') LIKE :q OR router_inventories.mac_id LIKE :q OR " +
        "router_inventories.name LIKE :q OR upgrades.time_zone LIKE :q OR " +
        "CONCAT((router_inventories.name), ' (', (router_inventories.mac_id), ')') LIKE :q"
        params_hash = { q: search_term }
        upgrades = upgrades.where(where_clause, params_hash)
      end

      draw = params[:draw].to_i
      total_records = current_user.organisation.upgrades.count
      filtered_records = upgrades.count

      # Server-side sorting
      if params[:order].present? && params[:columns].present?
        order_params = params[:order]['0'] || params[:order][0] || params[:order].first
        if order_params
          col_index = order_params[:column] || order_params['column']
          dir = order_params[:dir] || order_params['dir'] || 'asc'
          # Map DataTables column index to actual DB column
          columns = params[:columns].map { |_, v| v['data'] || v[:data] } if params[:columns].is_a?(Hash)
          columns ||= params[:columns].map { |v| v['data'] || v[:data] } if params[:columns].is_a?(Array)
          columns ||= %w[version mac_id schedule_at status created_at]
          col_name = columns[col_index.to_i] rescue nil
          # Whitelist allowed columns for sorting
          allowed = {
            'version' => 'upgrades.version',
            'mac_id' => 'router_inventories.mac_id',
            'aps' => 'upgrades.aps',
            'schedule_at' => 'COALESCE(upgrades.schedule_at, upgrades.created_at)',
            'status' => 'upgrades.status',
            'created_at' => 'upgrades.created_at',
            'updated_at' => 'upgrades.updated_at',
            'id' => 'upgrades.id'
          }
          if allowed[col_name]
            if col_name == 'mac_id'
              upgrades = upgrades.joins("LEFT OUTER JOIN router_inventories ON router_inventories.id = upgrades.router_inventory_id")
              upgrades = upgrades.order("router_inventories.mac_id #{dir == 'desc' ? 'DESC' : 'ASC'}")
            else
              upgrades = upgrades.order("#{allowed[col_name]} #{dir == 'desc' ? 'DESC' : 'ASC'}")
            end
          end
        end
      end

      # Pagination
      if params[:start].present? && params[:length].present?
        upgrades = upgrades.offset(params[:start].to_i).limit(params[:length].to_i)
      end

      # Eager load router_inventories only for the current page
     upgrades = upgrades.includes(:router_inventories)

      data = upgrades.map do |upgrade|
        mac_ids = []
        device_names = []
        router_inventory_ids = []
        mac_ids = [upgrade.router_inventory.mac_id].compact
        device_names = [upgrade.router_inventory.name.presence || ""]
        router_inventory_ids = [upgrade.router_inventory.id] if upgrade.router_inventory
        {
          id: upgrade.id,
          version: upgrade.version,
          aps: upgrade.aps,
          mac_id: mac_ids,
          device_names: device_names,
          router_inventory_ids: router_inventory_ids,
          schedule_type: upgrade.schedule_type,
          schedule_at: upgrade.schedule_at,
          time_zone: upgrade.time_zone,
          status: upgrade.status,
          created_at: upgrade.created_at,
          updated_at: upgrade.updated_at
        }
      end

      render json: {
        draw: draw,
        recordsTotal: total_records,
        recordsFiltered: filtered_records,
        data: data
      }
    rescue => e
      render json: { error: e.message }, status: :internal_server_error
    end
  end

  private

    def current_ability
      if cache_exist?
        @current_ability ||= Ability::UpgradeAbility.new(current_user)
      else
        @current_ability ||= Ability.new(current_user)
      end
    end
    
    # Use callbacks to share common setup or constraints between actions.
    def set_upgrade
      @upgrade = Upgrade.where(:id => params[:id]).first
      if @upgrade.blank?
        if request.format.json?
          render json: {message: "Requested Upgrade not found!", status: 404}, status: 404
        else
          flash[:error] = "Requested Upgrade not found!"
          redirect_to :action=>:index
        end
      end
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def upgrade_params
      params.require(:upgrade).permit(:version, :upgrade_type, :schedule_type, :time_zone, :schedule_at, :save_prev_config, :aps => [])
    end
end
