You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: telegram_helper.rb
    path of file: ./repos/zammad/lib
    
    the code of the file until where you have to start completion: # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/

require 'telegram/bot'

class TelegramHelper

  attr_accessor :client

=begin

check token and return bot attributes of token

  bot = TelegramHelper.check_token('token')

=end

  def self.check_token(token)
    result = nil
    begin
      Telegram::Bot::Client.run(token) do |bot|
        result = bot.api.getMe
      end
    rescue
      raise Exceptions::UnprocessableEntity, 'invalid api token'
    end
    result
  end

=begin

set webhook for bot

  success = TelegramHelper.set_webhook('token', callback_url)

returns

  true|false

=end

  def self.set_webhook(token, callback_url)
    if callback_url.match?(%r{^http://}i)
      raise Exceptions::UnprocessableEntity, __('The Telegram integration can only be configured on systems using the HTTPS protocol.')
    end

    begin
      Telegram::Bot::Client.run(token) do |bot|
        bot.api.setWebhook(url: callback_url)
      end
    rescue
      raise Exceptions::UnprocessableEntity, __('The webhook could not be saved by Telegram, seems to be an invalid URL.')
    end
    true
  end

=begin

create or update channel, store bot attributes and verify token

  channel = TelegramHelper.create_or_update_channel('token', params)

returns

  channel # instance of Channel

=end

  def self.create_or_update_channel(token, params, channel = nil)

    # verify token
    bot = check_token(token)

    if !channel && bot_duplicate?(bot.id)
      raise Exceptions::UnprocessableEntity, __('This bot already exists.')
    end

    if params[:group_id].blank?
      raise Exceptions::UnprocessableEntity, __("The required parameter 'group_id' is missing.")
    end

    group = Group.find_by(id: params[:group_id])
    if !group
      raise Exceptions::UnprocessableEntity, __("The required parameter 'group_id' is invalid.")
    end

    # generate random callback token
    callback_token = if Rails.env.test?
                       'callback_token'
                     else
                       SecureRandom.urlsafe_base64(10)
                     end

    # set webhook / callback url for this bot @ telegram
    callback_url = "#{Setting.get('http_type')}://#{Setting.get('fqdn')}/api/v1/channels_telegram_webhook/#{callback_token}?bid=#{bot.id}"
    set_webhook(token, callback_url)

    if !channel
      channel = bot_by_bot_id(bot.id)
      if !channel
        channel = Channel.new
      end
    end
    channel.area = 'Telegram::Bot'
    channel.options = {
      bot:            {
        id:         bot.id,
        username:   bot.username,
        first_name: bot.first_name,
        last_name:  bot.last_name,
      },
      callback_token: callback_token,
      callback_url:   callback_url,
      api_token:      token,
      welcome:        params[:welcome],
      goodbye:        params[:goodbye],
    }
    channel.group_id = group.id
    channel.active = true
    channel.save!
    channel
  end

=begin

check if bot already exists as channel

  success = TelegramHelper.bot_duplicate?(bot_id)

returns

  channel # instance of Channel

=end

  def self.bot_duplicate?(bot_id, channel_id = nil)
    Channel.where(area: 'Telegram::Bot').each do |channel|
      next if !channel.options
      next if !channel.options[:bot]
      next if !channel.options[:bot][:id]
      next if channel.options[:bot][:id] != bot_id
      next if channel.id.to_s == channel_id.to_s

      return true
    end
    false
  end

=begin

get channel by bot_id

  channel = TelegramHelper.bot_by_bot_id(bot_id)

returns

  true|false

=end

  def self.bot_by_bot_id(bot_id)
    Channel.where(area: 'Telegram::Bot').each do |channel|
      next if !channel.options
      next if !channel.options[:bot]
      next if !channel.options[:bot][:id]
      return channel if channel.options[:bot][:id].to_s == bot_id.to_s
    end
    nil
  end

=begin

generate message_id for message

  message_id = TelegramHelper.message_id(message)

returns

  message_id # 123456@telegram

=end

  def self.message_id(params)
    message_id = nil
    %i[message edited_message].each do |key|
      next if !params[key]
      next if !params[key][:message_id]

      message_id = params[key][:message_id]
      break
    end
    if message_id
      %i[message edited_message].each do |key|
        next if !params[key]
        next if !params[key][:chat]
        next if !params[key][:chat][:id]

        message_id = "#{message_id}.#{params[key][:
    
  def to_group(params, group_id, channel)
    # begin import
    Rails.logger.debug { 'import message' }

    # map channel_post params to message
    if params[:channel_post]
      return if params[:channel_post][:new_chat_title] # happens when channel title is renamed, we use [:chat][:title] already, safely ignore this.

      # NOTE: used .blank? which is a rails method. empty? does not work on integers (values like date, width, height)  to check.
      # need delete_if to remove any empty hashes, .compact only removes keys with nil values.
      params[:message] = {
        document:   {
          file_name: params.dig(:channel_post, :document, :file_name),
          mime_type: params.dig(:channel_post, :document, :mime_type),
          file_id:   params.dig(:channel_post, :document, :file_id),
          file_size: params.dig(:channel_post, :document, :file_size),
          thumb:     {
            file_id:   params.dig(:channel_post, :document, :thumb, :file_id),
            file_size: params.dig(:channel_post, :document, :thumb, :file_size),
            width:     params.dig(:channel_post, :document, :thumb, :width),
            height:    params.dig(:channel_post, :document, :thumb, :height)
          }.compact
        }.compact_blank!,
        video:      {
          duration:  params.dig(:channel_post, :video, :duration),
          width:     params.dig(:channel_post, :video, :width),
          height:    params.dig(:channel_post, :video, :height),
          mime_type: params.dig(:channel_post, :video, :mime_type),
          file_id:   params.dig(:channel_post, :video, :file_id),
          file_size: params.dig(:channel_post, :video, :file_size),
          thumb:     {
            file_id:   params.dig(:channel_post, :video, :thumb, :file_id),
            file_size: params.dig(:channel_post, :video, :thumb, :file_size),
            width:     params.dig(:channel_post, :video, :thumb, :width),
            height:    params.dig(:channel_post, :video, :thumb, :height)
          }.compact
        }.compact_blank!,
        voice:      {
          duration:  params.dig(:channel_post, :voice, :duration),
          mime_type: params.dig(:channel_post, :voice, :mime_type),
          file_id:   params.dig(:channel_post, :voice, :file_id),
          file_size: params.dig(:channel_post, :voice, :file_size)
        }.compact,
        sticker:    {
          width:     params.dig(:channel_post, :sticker, :width),
          height:    params.dig(:channel_post, :sticker, :height),
          emoji:     params.dig(:channel_post, :sticker, :emoji),
          set_name:  params.dig(:channel_post, :sticker, :set_name),
          file_id:   params.dig(:channel_post, :sticker, :file_id),
          file_path: params.dig(:channel_post, :sticker, :file_path),
          file_size: params.dig(:channel_post, :sticker, :file_size),
          thumb:     {
            file_id:   params.dig(:channel_post, :sticker, :thumb, :file_id),
            file_size: params.dig(:channel_post, :sticker, :thumb, :file_size),
            width:     params.dig(:channel_post, :sticker, :thumb, :width),
            height:    params.dig(:channel_post, :sticker, :thumb, :height),
            file_path: params.dig(:channel_post, :sticker, :thumb, :file_path)
          }.compact
        }.compact_blank!,
        chat:       {
          id:         params.dig(:channel_post, :chat, :id),
          first_name: params.dig(:channel_post, :chat, :title),
          last_name:  'Channel',
          username:   "channel#{params.dig(:channel_post, :chat, :id)}"
        },
        from:       {
          id:         params.dig(:channel_post, :chat, :id),
          first_name: params.dig(:channel_post, :chat, :title),
          last_name:  'Channel',
          username:   "channel#{params.dig(:channel_post, :chat, :id)}"
        },
        caption:    params.dig(:channel_post, :caption) || {},
        date:       params.dig(:channel_post, :date),
        message_id: params.dig(:channel_post, :message_id),
        text:       params.dig(:channel_post, :text),
        photo:      (params[:channel_post][:photo].map { |photo| { file_id: photo[:file_id], file_size: photo[:file_size], width: photo[:width], height: photo[:height] } } if params.dig(:channel_post, :photo))
      }.compact_blank!
      params.delete(:channel_post) # discard unused :channel_post hash
    end

    # checks if the channel post is being edited, and map it when it is
    if params[:edited_channel_post]
      # updates on telegram can only be on messages, no attachments
      params[:edited_message] = {
        chat:       {
          id:         params.dig(:edited_channel_post, :chat, :id),
          first_name: params.dig(:edited_channel_post, :chat, :title),
          last_name:  'Channel',
          username:   "channel#{params.dig(:edited_channel_post, :chat, :id)}"
        },
        from:       {
          id:         params.dig(:edited_channel_post, :chat, :id),
          first_name: params.dig(:edited_channel_post, :chat, :title),
          last_name:  'Channel',
          username:   "channel#{params.dig(:edited_channel_post, :chat, :id)}"
        },
        date:       params.dig(:edited_channel_post, :date),
        edit_date:  params.dig(:edited_channel_post, :edit_date),
        message_id: params.dig(:edited_channel_post, :message_id),
        text:       params.dig(:edited_channel_post, :text)
      }
      params.delete(:edited_channel_post) # discard unused :edited_channel_post hash
    end