
class HomeController < ApplicationController
  include CacheExistence
  before_filter :authenticate_user!
  before_filter :check_permission, only: :show
  before_filter :dashboard_topbar ,:except=>[:verify_mac_id]
  before_filter :check_destroy_permission, only: [:destroy]
  load_and_authorize_resource :class => LocationNetwork
  skip_authorize_resource :only => [:show,:verify_mac_id]
  skip_load_resource :only => [:new, :create, :showing_tag]

  rescue_from ActiveRecord::RecordNotFound do |exception|
        redirect_to root_url
      end

  def index
    unless @current_network.blank?
      @network_ssid = @current_network.network_ssids
      @network_wired_configs = @current_network.wired_configs
      redirect_to home_path(@current_network) and return
    end

    render :action=> :show
  end

  def new
    @network = LocationNetwork.new
    @existing_network = current_user.location_networks.where(network_template: true)
    @int_types = IntegrationType.where(vendor_name: "ruckus",:organisation_id=>current_user.organisation.id)
    # @access_points = current_user.router_inventories.blank? ? nil : current_user.router_inventories.where("location_network_id is null")
  end

  def create
    device = params[:router_inventories][:mac_id]
    unless device.blank?
      device = device.split(',').map(&:strip)
      location_network_id = nil
      device.each do |router|
        router = router.try(:upcase).gsub(/(.{2})/,'\1:').slice(0,17) if router.length == 12
        exist_router_inventory = RouterInventory.where(mac_id:router).first
        if exist_router_inventory.present? && exist_router_inventory.is_auto_provisioned? == true
          location_network_id = exist_router_inventory.location_network_id
          break if location_network_id.present?
        end
      end
    end
    if location_network_id.present?
      params[:location_network][:cloned_network_id] = location_network_id
      params[:location_network][:network_configuration] = "clone"
      @network = current_user.location_networks.build(location_network_params)
    else
      @network = current_user.location_networks.build(location_network_params)
    end
    @network.organisation_id = current_user.organisation.id unless current_user.organisation.blank?
    @network.tag_list.add(params["tag"]["add"], parse: true)
    if @network.save
      flash[:success] = "Successfully created new Network #{@network.network_name}"
      #current_user.unities.create(:location_network_id=>@network.id,:role_id=>Role.find_by_name('admin').id)
      inventory = router_inventory_params[:mac_id]
      unless inventory.blank?
        inventory = inventory.split(',').map(&:strip)
        inventory.each do |router|
          router = router.try(:upcase).gsub(/(.{2})/,'\1:').slice(0,17) if router.length == 12
          device = current_user.organisation.router_inventories.where(mac_id: router).last
          if device.present? && device.location_network_id.blank?
            device.location_network_id = @network.id
            device.save
          else
            RouterInventory.router_activation([router,@network.network_name, @network.vendor_type],current_user,false)
          end
        end
      end
      redirect_to home_path(@network)
    else
      flash[:error] = "Oops! there was some problem in creating Network. #{@network.errors.full_messages}"
      Rails.logger.warn "#{@network.errors.full_messages}"
      @int_types = IntegrationType.where(vendor_name: "ruckus",:organisation_id=>current_user.organisation.id)
      render new_home_path
    end
  end

  def edit
    @network = current_user.location_networks.find(params[:id])
  end

  def update
    @network = current_user.location_networks.find(params[:id])
    prev_network = @network.deep_dup
    prev_timezone = @network.timezone 
    if @network.update_attributes(update_location_network_params)
      if prev_timezone != @network.timezone
        @network.__elasticsearch__.index_document rescue nil
      end
      unless @network.network_name == prev_network.network_name || @network.timezone == prev_network.timezone
        PublicActivity::Activity.create(trackable_id: current_user.id, trackable_type: "LocationNetwork", owner_id: current_user.id, owner_type: "User", key: "location_network.update", organisation_id: current_user.organisation_id, location_network_id: current_user.location_networks.present? ? current_user.location_networks.first.id : nil, parameters: {:attributes => {"location_network(#{@network.network_name})" => {"name" => [prev_network.network_name, @network.network_name], "timezone" => [prev_network.timezone, @network.timezone]}}}, assumed_by: session[:assume_user])
      end
      flash[:success] = "Successfully updated the network #{@network.network_name}"
      redirect_to home_path @network
    else
      flash[:error] = "Oops! there was some problem in updating networki.  #{@network.errors.full_messages}"
      Rails.logger.warn "#{@network.errors.full_messages}"
      render edit_home_path(id: @network.try(:id))
    end
  end

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

  def bulk_update
    @ids = []
    json_data = {msg: 'No action performed', status: 200}
    
    unless params[:locations].blank?
      case params[:button]
      when "add_tag"
        unless params[:tag][:add].blank?
          tag_names = params[:tag][:add].split(',').map { |tag| tag.strip }.reject { |tag| tag.blank? }
          locations = LocationNetwork.where(id: params[:locations])
          
          # Process tags in bulk
          locations.each do |ln|
            prev_tag = ln.tag_list.deep_dup
            ln.tag_list.add(tag_names)
            @ids << ln.id unless ln.save
          end
          
          # Find relevant users once instead of repeatedly
          tagged_users = current_user.organisation.users.joins(:tags)
                          .where(tags: {name: tag_names})
                          .distinct
          
          # Create necessary unities in bulk
          unities_to_create = []
          tagged_users.each do |user|
            locations.each do |ln|
              unities_to_create << {
                user_id: user.id,
                location_network_id: ln.id, 
                role_id: user.role_id, 
                permission: 'full'
              }
            end
          end
          
          # Bulk insert using activerecord-import if available, otherwise fallback
          if defined?(Unity.import)
            Unity.import(unities_to_create, validate: true, on_duplicate_key_ignore: true)
          else
            unities_to_create.each do |unity_attrs|
              user = User.find(unity_attrs[:user_id])
              unless user.unities.exists?({location_network_id: unity_attrs[:location_network_id]})
                user_attrs = unity_attrs.dup
                user_attrs.delete(:user_id)
                user.unities.create(user_attrs)
              end
            end
          end
          
          @result = status_message(@ids.count, 'add_tag')
        else
          @result = [:error, 'Tag name cannot be blank']
          json_data = {msg: @result[1], status: 422}
        end
        
      when "remove_tag"
        unless params[:tag][:remove].blank?
          tag_names = Array(params[:tag][:remove])
          # Handle both string and array formats, clean up whitespace
          tag_names = tag_names.flat_map { |tag| tag.to_s.split(',') }.map { |tag| tag.strip }.reject { |tag| tag.blank? }
          locations = LocationNetwork.where(id: params[:locations])
          
          # Find all users with these tags once
          tagged_users = current_user.organisation.users.joins(:tags)
                          .where(tags: {name: tag_names})
                          .distinct
          
          # Create a map of user IDs to their location networks for efficient lookup
          user_locations_to_remove = {}
          tagged_users.each do |user|
            user_locations_to_remove[user.id] = locations.pluck(:id)
          end
          
          # Bulk delete unities
          if user_locations_to_remove.any?
            user_locations_to_remove.each do |user_id, location_ids|
              Unity.where(user_id: user_id, location_network_id: location_ids).delete_all
            end
          end
          
          # Remove tags from locations
          locations.each do |ln|
            ln.tag_list.remove(tag_names)
            @ids << ln.id unless ln.save
          end
          
          @result = status_message(@ids.count, 'remove_tag')
        else
          @result = [:error, 'Tag name cannot be blank']
          json_data = {msg: @result, status: 422}
        end
      when "remove_network"
        unless params[:locations].blank?
          locations = LocationNetwork.where(id: params[:locations])
          
          # Bulk destroy with error tracking
          locations.each do |ln|
            @ids << ln.id unless ln.destroy
          end
          
          @result = status_message(@ids.count, 'remove_network')
        else
          @result = [:error, 'Network cannot be blank']
          json_data = {msg: @result[1], status: 422}
        end
      end
      
      # Set flash message and prepare JSON response
      if @result
        flash[@result[0]] = @result[1]
        status_code = @result[0] == :error ? 422 : 200
        json_data = {msg: @result[1], status: status_code}
      end
    else
      @result = [:error, 'No locations selected']
      flash[@result[0]] = @result[1]
      json_data = {msg: @result[1], status: 422}
    end
    
    # Respond based on request format
    if request.format.json?
      render json: json_data, status: json_data[:status]
    else
      redirect_to :action => :network_list
    end
  end

  def status_message count,type
    status = msg = ''
    if count.to_i == 0
      status = :success
      if type == 'remove_from_network'
        msg = "Successfully removed the selected tags from network"
      elsif type == 'remove'
        msg = "Successfully removed selected tag"
      elsif type == 'new_network'
       msg = "Successfully created new network:<b>#{params[:network_name]}</b> and assigned selected tags to network"
      elsif type == 'existing_network'
        msg = "Successfully assigned the selected tag to network <b>#{@network.network_name}</b>"
      elsif type == 'add_tag'
        msg = "Successfully added tags to selected Network"
      elsif type == 'remove_tag'
        msg = "Successfully removed tags from selected Network"
      elsif type == 'add_init_template'
        msg = "Successfully added uplink config to selected Network"
      elsif type == 'remove_network'
        msg = "Successfully deleted selected Network"
      end
    else
      status = :error
      if type == 'remove_from_network'
        msg = "Oops! Following Network <b>#{@ids}</b> of tags were not been removed from network"
      elsif type == 'remove'
        msg = "Oops! Following Network <b>#{@ids}</b> of tags were not removed"
      elsif type == 'new_network'
       msg = "Oops! Following Network <b>#{@ids}</b> of tags were not assigned to network </b>#{params[:network_name]} </b>"
      elsif type == 'existing_network'
        msg = "Oops! Following Network <b>#{@ids}</b> of tags were not assigned to network #{@network.network_name}"
      elsif type == 'add_tag'
        msg = "Oops! For the following Network <b>#{@ids}</b> of  tags were not added"
      elsif type == 'remove_tag'
        msg = "Oops! For the following Network <b>#{@ids}</b> of  tags were not removed"
      elsif type == 'add_init_template'
        msg = "Oops! For the following Network <b>#{@ids}</b> of  uplink config not applied"
      elsif type == 'remove_network'
        msg = "Oops! For the following Network <b>#{@ids}</b> not removed"
      end
    end
    return status,msg
  end      

  def show
    unless params[:id].blank?
      change_network
    end
    @network_ssid = @current_network.network_ssids
    @network_wired_configs = @current_network.wired_configs
      @switch_configurations = @current_network.switch_configurations
    @aps_collection = @current_network.grouped_collection_of_ap_and_tags
    @network_vlans = @current_network.v_lans
  end
  
  def configure
    redirect_to :index if params[:id]
    current_user.current_network = params[:id]
    redirect_to :index
  end

  def verify_mac_id
    render :json=>{:status=>false} and return if params[:mac_id].blank?
    router = RouterInventory.validate_router(params[:mac_id],current_user.organisation, params[:allow_inventory_device] == 'true')
    render :json=>{:status=>true,:msg=>""} and return if router[0]
    render :json => {:status => false, :msg => router[1]}
  end

  def network_list
    @location_networks = current_user.location_networks
  end

  def destroy
    network = current_user.organisation.location_networks.find(params[:id])
    unless network.blank?
      unless network.router_inventories.present?
        if network.destroy
          flash[:success] = "Successfully deleted the Network #{network.network_name}"
        else
          flash[:error] = "Oops! there was some problem in deleting network"
          Rails.logger.warn "#{network.errors.full_messages}"
        end
      else
        flash[:warning] = "Oops! cannot delete network, Requested network has devices associated with it"
      end
    else
      flash[:warning] = "Requested Network is not found"
    end
    unless @current_network.try(:id) != network.id
      current_user.current_network = current_user.location_networks.first
      @current_network = current_user.current_network
    end
    redirect_to network_list_home_index_path
  end

  def verify_network_name
    network = current_user.organisation.location_networks.find_by :network_name => params[:network_name]
    status = network.blank? || network.id.to_s.eql?(params[:network_id]) ? true : false
    render :json => {value: status}
  end

  private

  def current_ability
    if cache_exist?
      @current_ability ||= Ability::NetworkSsidAbility.new(current_user).merge(Ability::WiredConfigAbility.new(current_user)).merge(Ability::VLanAbility.new(current_user)).merge(Ability::SwitchConfigurationAbility.new(current_user))
    else
      @current_ability ||= Ability.new(current_user)  
    end
  end

  def check_destroy_permission
    if current_user.is_tier_3? 
      template = current_user.organisation.location_networks.find_by_id(params[:id]).try(:network_template) 
      if template == true
        flash[:alert] = "You are not authorized to delete template network"
        redirect_to request.referer || root_path
      end
    elsif current_user.is_tier_2?
      flash[:alert] = "You are not authorized to perform this operation"
      redirect_to request.referer || root_path
    end
  end

  def location_network_params
    params.require(:location_network).permit(:network_name, :timezone,:cloned_network_id,:network_configuration,:presence, :presence_url, :vendor_type, :integration_type_id, :external_guid, :vendor_details => [:domain_id]).merge(model_current_user: current_user)
  end

  def update_location_network_params
    params.require(:location_network).permit(:network_name, :timezone, :presence, :presence_url, :network_template, :vendor_type, :external_guid)
  end

  def router_inventory_params
    params.require(:router_inventories).permit(:mac_id)
  end

  def change_network
    network = current_user.location_networks.find_by_id(params[:id])
    unless network.present?
      network = current_user.location_networks.first
      if network.blank?
        flash[:notice] = "You don't have access of any network"
        redirect_to root_url
      end
      flash[:notice] = "Your network has been changed to #{network.network_name}" if network.present?
    end
    current_user.current_network = network.id if network.present?
    @current_network = current_user.current_network
    logger.info("Current Network in show <<<<<<#{@current_network.id}") unless @current_network.blank?
  end

  def check_permission
    if !can?(:read, NetworkSsid) && !can?(:read, WiredConfig) && !can?(:read, VLan) && !can?(:read, SwitchConfiguration) 
      raise CanCan::AccessDenied.new("You are not authorized to perform this action!")
    end
  end
end
