namespace :data do
  desc "Remove tags from LocationNetwork and RouterInventory if present in external_guid (optimized)"
  task remove_tags_from_external_guid: :environment do
    puts "Starting to remove tags from external_guid columns..."
    updated_network_ids = []
    updated_router_ids = []
    removed_tag_ids = []

    # Process LocationNetwork records
    puts "Processing LocationNetwork records..."
    location_network_tags = ActsAsTaggableOn::Tag.
      joins(:taggings).
      joins("JOIN location_networks ln ON ln.id = taggings.taggable_id").
      where(taggings: { taggable_type: "LocationNetwork" }).
      where("ln.external_guid IS NOT NULL AND ln.external_guid != ''").
      pluck("taggings.id", "taggings.taggable_id", "tags.name", "tags.id", "ln.external_guid")
    
    puts "Found #{location_network_tags.size} potential tags to remove from LocationNetworks"
    
    # Group by network ID for batch processing
    network_tag_groups = location_network_tags.group_by { |item| item[1] } # group by taggable_id
    
    network_tag_groups.each_slice(100) do |batch_groups|
      network_ids = batch_groups.map(&:first)
      networks = LocationNetwork.where(id: network_ids).index_by(&:id)
      
      batch_groups.each do |network_id, tag_items|
        network = networks[network_id]
        next unless network
        next unless network.external_guid.present?
        
        external_guids = network.external_guid.split(',').map(&:strip)
        
        tag_items.each do |tagging_id, _, tag_name, tag_id , _|
          # Only process 36-character tags (GUIDs) that exist in external_guid
          next unless tag_name.length == 36
          next unless external_guids.include?(tag_name)
          
          # Remove the tagging directly without callbacks
          ActsAsTaggableOn::Tagging.where(id: tagging_id).delete_all
          updated_network_ids << network_id
          removed_tag_ids << tag_id
          puts "Removed tag #{tag_name} from LocationNetwork ID #{network_id}"
        end
      end
    end
    
    # Process RouterInventory records
    puts "Processing RouterInventory records..."
    router_inventory_tags = ActsAsTaggableOn::Tag.
      joins(:taggings).
      joins("JOIN router_inventories ri ON ri.id = taggings.taggable_id").
      where(taggings: { taggable_type: "RouterInventory" }).
      where("ri.external_guid IS NOT NULL AND ri.external_guid != ''").
      pluck("taggings.id", "taggings.taggable_id", "tags.name", "tags.id", "ri.external_guid")
    
    puts "Found #{router_inventory_tags.size} potential tags to remove from RouterInventories"
    
    # Group by router ID for batch processing
    router_tag_groups = router_inventory_tags.group_by { |item| item[1] } # group by taggable_id
    
    router_tag_groups.each_slice(100) do |batch_groups|
      router_ids = batch_groups.map(&:first)
      routers = RouterInventory.where(id: router_ids).index_by(&:id)
      
      batch_groups.each do |router_id, tag_items|
        router = routers[router_id]
        next unless router
        next unless router.external_guid.present?
        
        external_guids = router.external_guid.split(',').map(&:strip)
        
        tag_items.each do |tagging_id, _, tag_name, tag_id , _|
          # Only process 36-character tags (GUIDs) that exist in external_guid
          next unless tag_name.length == 36
          next unless external_guids.include?(tag_name)
          
          # Remove the tagging directly without callbacks
          ActsAsTaggableOn::Tagging.where(id: tagging_id).delete_all
          updated_router_ids << router_id
          removed_tag_ids << tag_id
          puts "Removed tag #{tag_name} from RouterInventory ID #{router_id}"
          
          # Update Redis for router inventory
          begin
            $redis.hset "AP:#{router.mac_id}", "Tags", router.tags.blank? ? "" : router.tags.map(&:name).join(',')
          rescue => e
            puts "Redis update failed for RouterInventory #{router_id}: #{e.message}"
          end
        end
      end
    end
    
    # Elasticsearch reindexing for LocationNetwork
    unless updated_network_ids.empty?
      puts "Reindexing #{updated_network_ids.uniq.size} LocationNetwork records..."
      
      batch_index = 0
      updated_network_ids.uniq.each_slice(100) do |batch_ids|
        batch_index += 1
        puts "Processing LocationNetwork batch #{batch_index}"
        
        networks = LocationNetwork.where(id: batch_ids).includes(:tags)
        
        bulk_body = networks.map do |network|
          tag_names = network.tags.pluck(:name)
          spaced_external_guid = network.external_guid.present? ? network.external_guid.split(',').map(&:strip).join(" ") : ""
          
          {
            update: {
              _index: LocationNetwork.index_name,
              _id: network.id,
              data: {
                doc: {
                  tags: tag_names,
                  tags_keyword: tag_names.join(" "),
                  tag_list: network.tag_list,
                  external_guid: spaced_external_guid
                }
              }
            }
          }
        end
        
        if bulk_body.any?
          begin
            LocationNetwork.__elasticsearch__.client.bulk(body: bulk_body)
            puts "Successfully updated LocationNetwork batch #{batch_index}"
          rescue => e
            puts "Error during LocationNetwork batch #{batch_index}: #{e.message}"
          end
        end
      end
    end
    
    # Elasticsearch reindexing for RouterInventory
    unless updated_router_ids.empty?
      puts "Reindexing #{updated_router_ids.uniq.size} RouterInventory records..."
      
      batch_index = 0
      updated_router_ids.uniq.each_slice(100) do |batch_ids|
        batch_index += 1
        puts "Processing RouterInventory batch #{batch_index}"
        
        routers = RouterInventory.where(id: batch_ids).includes(:tags)
        
        bulk_body = routers.map do |router|
          tag_names = router.tags.pluck(:name)
          spaced_external_guid = router.external_guid.present? ? router.external_guid.split(',').map(&:strip).join(" ") : ""
          
          {
            update: {
              _index: RouterInventory.index_name,
              _id: router.id,
              data: {
                doc: {
                  tags: tag_names,
                  tags_keyword: tag_names.join(" "),
                  tag_list: router.tag_list,
                  external_guid: spaced_external_guid
                }
              }
            }
          }
        end
        
        if bulk_body.any?
          begin
            RouterInventory.__elasticsearch__.client.bulk(body: bulk_body)
            puts "Successfully updated RouterInventory batch #{batch_index}"
          rescue => e
            puts "Error during RouterInventory batch #{batch_index}: #{e.message}"
          end
        end
      end
    end
    
    # Cleanup unused tags
    puts "Cleaning up unused tags..."
    ActsAsTaggableOn::Tag.where(id: removed_tag_ids.uniq).each do |tag|
      if tag.taggings.count == 0
        puts "Removing tag with name  #{tag.name}"
        tag.delete
      end
    end
    
    puts "Task completed!"
    puts "Updated #{updated_network_ids.uniq.size} LocationNetwork records"
    puts "Updated #{updated_router_ids.uniq.size} RouterInventory records"
  end
end