module Devops
  module API3
    module Routes
      module StackRoutes

        def self.registered(app)
          app.define_policy :read_stacks, 'Read stacks'
          app.define_policy :create_stacks, 'Create stacks'
          app.define_policy :update_stacks, 'Create stacks'
          app.define_policy :delete_stacks, 'Delete stacks'

          app.get_with_headers '/stacks' do
            check_policy(:read_stacks)
            json Devops::API3::Handler::Stack.new(request).stacks.map(&:to_hash)
          end

          app.get_with_headers '/stacks/provider/:provider' do |provider|
            check_policy(:read_stacks)
            check_provider(provider)
            json Devops::API3::Handler::Stack.new(request).stacks_for_provider(provider).map(&:to_hash)
          end

          app.get_with_headers '/stack/:name/servers' do |name|
            check_policy(:read_stacks)
            json Devops::API3::Handler::Stack.new(request).stack_servers(name).map(&:to_hash)
          end

          # Create stack
          #
          # * *Request*
          #   - method : POST
          #   - headers :
          #     - Accept: application/json
          #     - Content-Type: application/json
          #   - body :
          #     {
          #       "stack_attributes": {
          #         "project": "project_name",
          #         "deploy_env": "test",
          #         "provider": "ec2",
          #         "tags": {
          #           "tagName": "tagValue"
          #         },
          #         "parameters": {
          #           "KeyName": "Value"
          #         }
          #       }
          #       "without_bootstrap": false,
          #       "skip_rollback": false
          #     }
          #
          # * *Returns* :
          #   [task_id]
          app.post_with_headers "/stack" do
            check_policy(:create_stacks)
            json Devops::API3::Handler::Stack.new(request).create_stack
            #create_response "Created", nil, 201
          end

          hash = {}

          hash['GET'] = lambda { |stack_id|
            check_policy(:read_stacks)
            json Devops::API3::Handler::Stack.new(request).stack(stack_id).to_hash
          }

          hash['DELETE'] = lambda { |stack_id|
            check_policy(:delete_stacks)
            Devops::API3::Handler::Stack.new(request).delete_stack(stack_id)
            create_response("Stack '#{stack_id}' has been removed")
          }
          app.multi_routes '/stack/:stack_id', hash

          app.post_with_headers "/stack/:stack_id/sync" do |stack_id|
            check_policy(:update_stacks)
            json Devops::API3::Handler::Stack.new(request).sync(stack_id).to_hash
          end

=begin
TODO: delete?
          app.get_with_headers "/stack/:stack_id/resources" do |stack_id|
            check_policy(:read_stacks)
            json Devops::API3::Handler::Stack.new(request).resources(stack_id)
          end

          app.get_with_headers "/stack/:stack_id/resources/:resource_id" do |stack_id, resource_id|
            check_policy(:read_stacks)
            json Devops::API3::Handler::Stack.new(request).resource(stack_id, resource_id)
          end
=end

          # Set run_list to stack
          #
          # * *Request*
          #   - method : PATCH
          #   - headers :
          #     - Accept: application/json
          #     - Content-Type: application/json
          #   - body :
          #     [
          #       "role[role_1]",
          #       "recipe[recipe_1]"
          #     ]
          #
          # * *Returns* :
          #   200 - Updated
          app.patch_with_headers "/stack/:id/run_list" do |id|
            check_policy(:update_stacks)
            info = Devops::API3::Handler::Stack.new(request).set_run_list(id)
            create_response(info)
          end

          # Deploy stack instances
          #
          # * *Request*
          #   - method : POST
          #   - headers :
          #     - Accept: application/json
          #     - Content-Type: application/json
          #   - body :
          #     {
          #       "tags" : ["tag1", "tag2"]
          #     }
          #
          # * *Returns* :
          #   200 - Updated
          app.post_with_headers "/stack/:id/deploy" do |id|
            check_privileges("stack", "x")
            if request["X-Stream"]
              stream() do |out|
                status = []
                begin
                  status = Devops::API3::Handler::Stack.new(request).deploy_stream(id, out)
                  out << create_status(status)
                rescue IOError => e
                  logger.error e.message
                  break
                end
              end # stream
            else
              files = Devops::API3::Handler::Stack.new(request).deploy(id)
              sleep 1
              json files
            end
          end


          # Reserve stack instances
          #
          # * *Request*
          #   - method : POST
          #   - headers :
          #     - Accept: application/json
          #     - Content-Type: application/json
          #
          # * *Returns* :
          #   200 - OK
          app.post_with_headers "/stack/:id/reserve" do |id|
            check_policy(:read_stacks)
            check_privileges("server", "w")
            Devops::API3::Handler::Stack.new(request).reserve_servers(id)
            create_response("Servers of stack '#{id}' has been reserved")
          end

          # Unreserve stack instances
          #
          # * *Request*
          #   - method : POST
          #   - headers :
          #     - Accept: application/json
          #     - Content-Type: application/json
          #
          # * *Returns* :
          #   200 - OK
          app.post_with_headers "/stack/:id/unreserve" do |id|
            check_policy(:read_stacks)
            check_privileges("server", "w")
            Devops::API3::Handler::Stack.new(request).unreserve_servers(id)
            create_response("Servers of stack '#{id}' has been unreserved")
          end


          hash = {}
          # Add tags to stack instances
          #
          # * *Request*
          #   - method : PUT
          #   - headers :
          #     - Content-Type: application/json
          #   - body :
          #     {
          #       "tag name": "tag value"
          #     }
          #
          # * *Returns* :
          #   200 - Added
          hash["PUT"] = lambda {|id|
            check_policy(:update_stacks)
            Devops::API3::Handler::Stack.new(request).set_tags(id)
            create_response("Added")
          }

          # Delete tags from stack instances
          #
          # * *Request*
          #   - method : DELETE
          #   - headers :
          #     - Content-Type: application/json
          #   - body :
          #     {
          #       "tag name": "tag value"
          #     }
          #
          # * *Returns* :
          #   200 - Deleted
          hash["DELETE"] = lambda {|id|
            check_policy(:update_stacks)
            Devops::API3::Handler::Stack.new(request).unset_tags(id)
            create_response("Deleted")
          }
          app.multi_routes "/stack/:id/tags", hash

          # Change stack stack_template
          #
          # * *Request*
          #   - method : PUT
          #   - headers :
          #     - Accept: application/json
          #     - Content-Type: application/json
          #   - body :
          #     {
          #       "stack_template": "template_id"
          #     }
          #
          # * *Returns* :
          #   200 - OK
          app.put_with_headers "/stack/:id/stack_template" do |id|
            check_policy(:read_stacks)
            json Devops::API3::Handler::Stack.new(request).change_stack_template(id)
          end

          puts 'Stack routes initialized'
        end

      end
    end
  end
end
