# == Schema Information
#
# Table name: upgrades
#
#  id                  :integer          not null, primary key
#  version             :string(255)
#  aps                 :text
#  created_at          :datetime
#  updated_at          :datetime
#  organisation_id     :integer
#  router_inventory_id :integer
#  status              :string(255)
#  upgrade_type        :string(255)
#  schedule_type       :string(255)
#  schedule_at         :datetime
#  time_zone           :string(255)
#  worker_job_id       :string(255)
#  save_prev_config    :boolean          default(TRUE)
#

class Upgrade < ActiveRecord::Base
  resourcify
  include AssociatedResource
  include RedisWrapper
  include PublicActivity::Model

  tracked owner: ->(controller, model) { controller && controller.tracked_current_user },params: {:attributes => proc {|controller, model_instance| {"upgrade(#{model_instance.router_inventory.mac_id})"=> model_instance.changes}}},organisation_id: ->(controller, model) { controller && controller.tracked_current_user.organisation_id }

  tracked assumed_by: proc {|controller, model| controller.user_assumed_by if controller}

  belongs_to :router_inventory
  belongs_to :organisation

  before_save :set_networks_timezone
  before_save :set_schedule_at
  after_save :start_upgrade_worker

  after_destroy do |x|
    redis_del "UPGRADE_#{x.router_inventory.mac_id}"
    Sidekiq::Status.unschedule x.worker_job_id unless x.worker_job_id.blank?
  end

  scope :pending, -> { where(status: nil) }
  scope :sent, -> { where(status: "sent") }

  def json_build
    {id: self.id, version: self.version, aps: self.aps, organisation_id: self.organisation_id, router_inventory_id: self.router_inventory_id, status: self.status, upgrade_type: self.upgrade_type, schedule_type: self.schedule_type, schedule_at: self.schedule_at, time_zone: self.time_zone, worker_job_id: self.worker_job_id, save_prev_config: self.save_prev_config}
  end

  def schedule_upgrade_worker
    logger.info "<<<<<<<<<<<<<<<<< New worker >>>>>>>>>>>>>>>>>>>>>"
    job_id = UpgradeApWorker.perform_at(self.schedule_at, self.id)
    self.update_column(:worker_job_id, job_id)
  end

  def schedule_at_with_timezone
    self.schedule_at.blank? ? nil : ActiveSupport::TimeZone[self.time_zone].parse(self.schedule_at.to_s)
  end

  def set_redis
    up_version = self.upgrade_type.eql?("manual") ? self.version : UpgradeData.last.version
    upgrade_data = UpgradeData.find_by(version: up_version)
    hw_part_no = self.router_inventory.hardware_part.try(:part_number)
    redis_key = "AP:#{self.router_inventory.mac_id}"

    if self.router_inventory.vendor_type.eql?("4") || self.router_inventory.vendor_type.eql?("6")
      if self.router_inventory.is_actual_up?
        begin
          $redis.hset(redis_key, "ongoing_upgrade", true)
          res = OpenWifi::ProvisioningService.new(self.router_inventory.location_network, self.router_inventory.organisation).upgrade(self.router_inventory, upgrade_data.url[hw_part_no])

          if res['results'].present? && res['results']['status'].present? && res['results']['status']['error'] == 0 && res['status'] == 'completed'
            self.update_columns(status: "sent", updated_at: Time.zone.now)
            $redis.hdel(redis_key, "pending_upgrade")
            Rails.logger.info "[OPENWIFI] [UPGRADE] [#{self.router_inventory.mac_id}] Upgrade successfully initiated. Removed pending_upgrade flag."
          elsif res["status"] == "pending"
            self.update_columns(status: "waiting for response", updated_at: Time.zone.now)
            $redis.hset(redis_key, "upgrade_uuid", res["UUID"])
            $redis.hset(redis_key, "pending_upgrade", self.id)
            Rails.logger.info "[OPENWIFI] [UPGRADE] [#{self.router_inventory.mac_id}] Waiting for response."
          else
            self.update_columns(status: "failed", updated_at: Time.zone.now)
            Rails.logger.error "[OPENWIFI] [UPGRADE] [#{self.router_inventory.mac_id}] Failed to initiate upgrade. Response: #{res.body}"
            $redis.hdel(redis_key, "pending_upgrade")
          end
        ensure
          $redis.hdel(redis_key, "ongoing_upgrade")
        end
      else
        $redis.hset(redis_key, "pending_upgrade", self.id)
        Rails.logger.info "[OPENWIFI] [UPGRADE] [#{self.router_inventory.mac_id}] Upgrade initiated. Added pending_upgrade flag."
      end
      return
    end

    unless upgrade_data.blank? || upgrade_data.url[hw_part_no].blank?
      upgrade = {
        "NASID" => self.router_inventory.mac_id,
        "ENABLE" => 1,
        "URL" => upgrade_data.url[hw_part_no],
        "SAVE_CFG" => self.save_prev_config? ? 1 : 0
      }
      #upgrade['TYPE'] = upgrade_data.upgrade_category.to_i if upgrade_data.is_4g_module_upgrade?
      redis_set "UPGRADE_#{self.router_inventory.mac_id}", upgrade.to_json
      self.update_columns(status: "waiting for response", updated_at: Time.zone.now)
    end
  end

  def pending?
    self.status.nil?
  end

  private

    def set_schedule_at
      self.schedule_at = self.schedule_type.eql?('schedule') && self.schedule_at.present? ? ActiveSupport::TimeZone[self.time_zone].parse(self.schedule_at.strftime("%Y-%m-%d %H:%M")) : nil
    end

    def set_networks_timezone
      if self.time_zone.eql?('networks_timezone')
        ln = self.router_inventory.location_network
        network_timezone = ln.blank? ? 'UTC' : ln.timezone
        self.time_zone = network_timezone
      end
    end

    def start_upgrade_worker
      if(self.schedule_type.eql? "now")
        Sidekiq::Status.unschedule self.worker_job_id unless self.worker_job_id.blank?
        self.set_redis
      else
        redis_del "UPGRADE_#{self.router_inventory.mac_id}"
        #start worker to perform scheduled upgrade
        if self.schedule_at_changed?
          unless self.worker_job_id.present?
            logger.info "<<<<<<<<<<<<<<<<< No worker >>>>>>>>>>>>>>>>>>>>>"
            self.schedule_upgrade_worker unless self.schedule_at <= Time.zone.now.utc
          else
            worker = Sidekiq::Status.get_all self.worker_job_id
            logger.info "<<<<<<<<<<<<<<<<< worker = #{worker} >>>>>>>>>>>>>>>>>>>>>"
            Sidekiq::Status.unschedule self.worker_job_id unless worker.blank?

            self.schedule_upgrade_worker unless self.schedule_at <= Time.zone.now.utc
          end
        end
      end
    end
end
