# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require "rake/testtask"

Rake::TestTask.new "test" do |t|
  t.test_files = FileList["**/*_test.rb"]
  t.warning = false
end

$prefix = "google-cloud-ruby-samples"

namespace :fixtures do
  desc "Lists the existing KMS acceptance test fixtures for the project in us-east1"
  task :list do
    require "google/cloud/kms"
    client = Google::Cloud::Kms.key_management_service
    project_id = ENV["GOOGLE_CLOUD_PROJECT"] || raise("missing GOOGLE_CLOUD_PROJECT")
    location_id = "us-east1"
    location_name = client.location_path project: project_id, location: location_id

    puts "\nkey rings (filter: \"name: #{$prefix}-key-ring-\"):\n\n"
    client.list_key_rings(parent: location_name, filter: "name: #{$prefix}-key-ring-", order_by: "name").each do |kr|
      puts kr.name
    end

    key_ring_id = "#{$prefix}-key-ring-2"
    key_ring_name = client.key_ring_path project: project_id, location: location_id, key_ring: key_ring_id
    begin
      key_ring = client.get_key_ring name: key_ring_name
      puts "\ncrypto keys for key ring #{key_ring.name.split('/').last} (filter: \"name: cryptoKeys/#{$prefix}-\"):\n\n"
      client.list_crypto_keys(parent: key_ring.name, filter: "name: cryptoKeys/#{$prefix}-").each do |key|
        puts key.name.split("/").last
        puts "  primary version:"
        puts "  -  #{key.primary&.name&.split('/')&.last} - #{key.primary&.state}"
        puts "  all versions:"
        versions = client.list_crypto_key_versions(parent: key.name).to_a
        versions.each do |version|
          puts "  -  #{version.name.split('/').last} - #{version.state}"
        end
      end
    rescue Google::Cloud::NotFoundError
      puts "\nfixture key ring not found: #{key_ring_name}\n"
    end
  end

  desc "Creates the KMS acceptance test fixtures for the project in us-east1"
  task :create do
    require "google/cloud/kms"
    client = Google::Cloud::Kms.key_management_service
    project_id = ENV["GOOGLE_CLOUD_PROJECT"] || raise("missing GOOGLE_CLOUD_PROJECT")
    location_id = "us-east1"
    location_name = client.location_path project: project_id, location: location_id

    puts "\nkey ring:\n"

    key_ring_id = "#{$prefix}-key-ring-2"
    key_ring_name = client.key_ring_path project: project_id, location: location_id, key_ring: key_ring_id
    begin
      key_ring = client.get_key_ring name: key_ring_name
      puts "exists: #{key_ring.name}"
    rescue Google::Cloud::NotFoundError
      key_ring = client.create_key_ring parent: location_name, key_ring_id: key_ring_id, key_ring: {}
      puts "created: #{key_ring.name}"
    end

    puts "\ncrypto keys:\n"

    get_or_create_crypto_key client,
                             project_id,
                             location_id,
                             key_ring_id,
                             "asymmetric_sign_ec_key",
                             :ASYMMETRIC_SIGN,
                             :EC_SIGN_P256_SHA256

    get_or_create_crypto_key client,
                             project_id,
                             location_id,
                             key_ring_id,
                             "asymmetric_sign_rsa_key",
                             :ASYMMETRIC_SIGN,
                             :RSA_SIGN_PSS_2048_SHA256

    get_or_create_crypto_key client,
                             project_id,
                             location_id,
                             key_ring_id,
                             "symmetric_key",
                             :ENCRYPT_DECRYPT,
                             :GOOGLE_SYMMETRIC_ENCRYPTION

    get_or_create_crypto_key client,
                             project_id,
                             location_id,
                             key_ring_id,
                             "hsm_key",
                             :ENCRYPT_DECRYPT,
                             :GOOGLE_SYMMETRIC_ENCRYPTION,
                             protection_level: "HSM"

    get_or_create_crypto_key client,
                             project_id,
                             location_id,
                             key_ring_id,
                             "asymmetric_decrypt_key",
                             :ASYMMETRIC_DECRYPT,
                             :RSA_DECRYPT_OAEP_2048_SHA256

    get_or_create_crypto_key client,
                             project_id,
                             location_id,
                             key_ring_id,
                             "mac_key",
                             :MAC,
                             :HMAC_SHA256
  end
end

def get_or_create_crypto_key client, project_id, location_id, key_ring_id, id, purpose, algorithm, protection_level: nil
  key_id = "#{$prefix}-#{id}"
  key_name = client.crypto_key_path project:    project_id,
                                    location:   location_id,
                                    key_ring:   key_ring_id,
                                    crypto_key: key_id
  key = client.get_crypto_key name: key_name
  puts "exists: #{key.name}"
  key
rescue Google::Cloud::NotFoundError
  key_ring_name = client.key_ring_path project: project_id, location: location_id, key_ring: key_ring_id

  version_template = {
    algorithm: algorithm
  }
  version_template[:protection_level] = protection_level if protection_level
  key = client.create_crypto_key parent:        key_ring_name,
                                 crypto_key_id: key_id,
                                 crypto_key:    {
                                   purpose:          purpose,
                                   version_template: version_template,
                                   labels:           { "foo" => "bar", "zip" => "zap" }
                                 }
  puts "created: #{key.name}"
  key
end
