#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle install

# Create dummy application
rm -fr spec/dummy
bundle exec rails new spec/dummy --skip-git --skip-javascript --skip-hotwire --skip-jbuilder --skip-test --skip-bootsnap --force

echo "Changes to application"

sed -i 's/2.7.4/>= 2.7.4/' spec/dummy/Gemfile
sed -i '/end/i root "main#index"' spec/dummy/config/routes.rb
sed -i '/root "main#index"/i get  "create_job", to:  "main#create_job", as: "create_job"' spec/dummy/config/routes.rb
sed -i '/root "main#index"/i get  "send_email", to:  "main#send_email", as: "send_email"' spec/dummy/config/routes.rb
sed -i '/root "main#index"/i   get "health", to: "main#health"' spec/dummy/config/routes.rb

echo '
class MainController < ApplicationController
  include ActionView::Helpers::UrlHelper

   def index
     render inline: "#{link_to HelloWorldJob.name, create_job_path}<br>
                     #{link_to HelloWorldJob.name, create_job_path(wait: 1)}<br>
                     #{link_to SubscriptionMailer, send_email_path}"
   end

   def create_job
     j = HelloWorldJob
     if params[:wait]
       j = j.set(wait: params[:wait].to_i.minutes)
     end
     j.perform_later

     redirect_to root_path
   end

   def health
     head :ok
   end

   def send_email
     SubscriptionMailer.notify.deliver_later
     redirect_to root_path
   end

end
' > spec/dummy/app/controllers/main_controller.rb

echo '
Rails.application.configure do

  auth_options = {
    bearer_token_file: "/var/run/secrets/kubernetes.io/serviceaccount/token"
  }
  ssl_options = {}
  if File.exist?("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
    ssl_options[:ca_file] = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
  end
  api_endpoint = "https://kubernetes.default.svc"
  api_version = "v1"
  namespace = File.read("/var/run/secrets/kubernetes.io/serviceaccount/namespace")

  context = Kubeclient::Config::Context.new(
    api_endpoint,
    api_version,
    ssl_options,
    auth_options,
    namespace
  )

  default_manifest = YAML.safe_load(
    <<~MANIFEST
      apiVersion: batch/v1
      kind: Job
      metadata:
        name: scheduled-job-name
        namespace: default
      spec:
        template:
          spec:
            restartPolicy: Never
            containers:
            - name: app-job
              image: activejobk8s:0.1.0
              imagePullPolicy: IfNotPresent
              env:
                - name: RAILS_SERVE_STATIC_FILES
                  value: "1"
                - name: RAILS_LOG_TO_STDOUT
                  value: "1"
                - name: RAILS_ENV
                  value: "development"
              command: ["/bin/sh"]
              args:
                - "-ec"
                - "bundle install && bundle exec rails active_job_k8s:run_job"
              volumeMounts:
              - mountPath: /usr/src/app
                name: application-volume
            volumes:
            - name: application-volume
              hostPath:
                # directory location on host
                path: /application
  MANIFEST
  )

  config.active_job.queue_adapter = ActiveJob::QueueAdapters::K8sAdapter.new(
    kubeclient_context: context,
    default_manifest: default_manifest
  )

end
' > spec/dummy/config/initializers/active_job_k8s.rb

echo '
class HelloWorldJob < ApplicationJob
  queue_as :default

  def perform(*args)
    Rails.logger.debug "Hello World"
    sleep (SecureRandom.random_number * 50).to_i # simulate operations
    FileUtils.touch(Rails.root.join("tmp","#{SecureRandom.hex}.test"))
  end
end
' > spec/dummy/app/jobs/hello_world_job.rb

echo '
class SubscriptionMailer < ApplicationMailer
  def notify
    mail(to: "test@domain.tld", subject: "test", body: "message")
  end
end
'  > spec/dummy/app/mailers/subscription_mailer.rb

echo 'FROM ruby:3.0.4-alpine3.16

RUN apk update \
    && apk upgrade \
    && apk add --update alpine-conf bash tzdata build-base curl-dev curl git yaml-dev zlib-dev

RUN gem install bundler:2.3.7

# throw errors if Gemfile has been modified since Gemfile.lock
WORKDIR /usr/src/app/spec/dummy

COPY Gemfile Gemfile.lock ./
RUN bundle install

COPY . .

CMD ["/bin/sh", "-ec", "rm -fr /usr/src/app/spec/dummy/tmp/pids/* && bundle install && bundle exec rails s -b 0.0.0.0 -p 3000"]' > spec/dummy/Dockerfile

docker build -t activejobk8s:0.1.0 spec/dummy/.

# aggiungiamo la path ad active_job_k8s nel Gemfile che viene poi usato nel cluster e che punta alla gemma.
echo "gem 'active_job_k8s', path:'/usr/src/app' " >> spec/dummy/Gemfile


echo "START KIND ENV"
kind delete cluster -n active-job-cluster
kind create cluster --config bin/cluster.yaml
kubectl config set-context active-job-cluster

echo "SLEEP for cluster to be ready"
sleep 10

kind load docker-image activejobk8s:0.1.0 -n active-job-cluster

kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: test-activejobk8s
  namespace: default
  labels:
    app: active-job-app
spec:
  containers:
  - name: app
    image: activejobk8s:0.1.0
    imagePullPolicy: Never
    ports:
      - name: app
        containerPort: 3000
        protocol: TCP
    env:
      - name: RAILS_SERVE_STATIC_FILES
        value: '1'
      - name: RAILS_LOG_TO_STDOUT
        value: '1'
      - name: RAILS_ENV
        value: 'development'
    volumeMounts:
    - mountPath: /usr/src/app
      name: application-volume
    livenessProbe:
      httpGet:
        path: /health
        port: 3000
      initialDelaySeconds: 120
      periodSeconds: 3
  volumes:
  - name: application-volume
    hostPath:
      # directory location on host
      path: /application
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: jobs-edit
  namespace: default
rules:
  - apiGroups:
      - "batch"
    resources:
      - jobs
    verbs:
      - get
      - list
      - create
      - patch
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: jobs-edit
  namespace: default
subjects:
  - kind: ServiceAccount
    name: default
    namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: jobs-edit
---
apiVersion: v1
kind: Service
metadata:
  name: app-service
  namespace: default
  labels:
    app: app-service
spec:
  ports:
    - name: 3000-3000
      protocol: TCP
      port: 3000
      targetPort: 3000
      nodePort: 30335
  selector:
    app: active-job-app
  type: NodePort
EOF

echo "Open browser to 0.0.0.0:3000"
open http://0.0.0.0:3000
