class CreateStackJob < DockerApiJob
  queue_as :default

  # Takes hash: challenge
  #   user_id
  #   problem_id
  #   network
  #   services
  #   lifespan
  def perform(challenge)
    check_existing(challenge)
    create_stack(challenge)
  end

  private
    def check_existing(challenge)
      services = docker_get_services(challenge)
      networks = docker_get_networks(challenge)

      # If this user already has a stack initiated, reset it
      if networks.length > 0 or services.length > 0
        user_id = challenge['user_id']
        User.find(user_id).update_attribute(:container_id, '')
        User.find(user_id).update_attribute(:stack_expiry, DateTime.now)
        User.find(user_id).update_attribute(:problem_id, -1)
        delete_stack(services, networks)
      end
    end

    def create_stack(challenge)
      # Start with network (Name: problem_id-user_id)
      network = JSON(challenge['network'])
      network['Name'] = "hta-#{challenge['problem_id']}-#{challenge['user_id']}"
      network['Labels'] = {
        "user_id" => "#{challenge['user_id']}",
        "problem_id" => "#{challenge['problem_id']}",
        "lifetime" => "#{challenge['lifespan']}",
        "hackthearch" => "This network was generated by HackTheArch"
      }
      res = docker_post_request('/networks/create', network.to_json)
      network_id = JSON(res.body)["Id"]

      if res.code != '201'
        raise Exception.new("Couldn't create challenge network.")
      end

      # Then build services
      services = JSON(challenge['services'])
      services.each do |service|

        if service['Labels'].nil?
          service['Labels'] = {}
        end

        service['Labels']["user_id"] = "#{challenge['user_id']}"
        service['Labels']["problem_id"] = "#{challenge['problem_id']}"
        service['Labels']["lifetime"] = "#{challenge['lifespan']}"
        service['Labels']["hackthearch"] = "This service was generated by HackTheArch"

        # Make sure the service is reachable by its designed name
        service['Networks'] = [{ 
          "Target": network_id,
          "Aliases": [
            service['Name'],
            service['Name'].gsub("-","."),
          ]
        }]

        # find entrypoint
        is_entry = false
        if service['Name'].downcase == "entrypoint"
          is_entry = true
        end

        # Add user_id to service name for identification
        service_name = service['Name']
        service['Name'] = "hta-#{service_name}-#{challenge['user_id']}"

        res = docker_post_request('/services/create', service.to_json)
        if res.code != '201'
          raise Exception.new("Couldn't create challenge services.")
        end

        # If service is entry point, assign to user
        if is_entry
          id = JSON(res.body)["ID"]
          User.find(challenge['user_id']).update_attribute(:container_id, id)
          User.find(challenge['user_id']).update_attribute(:stack_expiry, DateTime.now + Integer(challenge['lifespan']).minutes)
          User.find(challenge['user_id']).update_attribute(:problem_id, challenge['problem_id'])
        end
      end
    end

end
