require "sfn"

module Sfn
  class Command
    class Destroy < Command
      include Sfn::CommandModule::Base

      # Run the stack destruction action
      def execute!
        name_required!
        stacks = name_args.sort
        plural = "s" if stacks.size > 1
        globs = stacks.find_all do |s|
          s !~ /^[a-zA-Z0-9-]+$/
        end
        unless globs.empty?
          glob_stacks = provider.connection.stacks.all.find_all do |remote_stack|
            globs.detect do |glob|
              File.fnmatch(glob, remote_stack.name)
            end
          end
          stacks += glob_stacks.map(&:name)
          stacks -= globs
          stacks.sort!
        end
        ui.warn "Destroying Stack#{plural}: #{ui.color(stacks.join(", "), :bold)}"
        ui.confirm "Destroy listed stack#{plural}?"
        stacks.each do |stack_name|
          stack = provider.connection.stacks.get(stack_name)
          if stack
            nested_stack_cleanup!(stack)
            begin
              api_action!(:api_stack => stack) do
                stack.destroy
              end
            rescue Miasma::Error::ApiError::RequestError => error
              raise unless error.response.code == 404
              # if stack is already gone, disable polling
              config[:poll] = false
            end
            ui.info "Destroy request complete for stack: #{ui.color(stack_name, :red)}"
          else
            ui.warn "Failed to locate requested stack: #{ui.color(stack_name, :bold)}"
          end
        end
        if config[:poll]
          if stacks.size == 1
            pstack = stacks.first
            begin
              poll_stack(pstack)
              stack = provider.connection.stacks.get(pstack)
              stack.reload
              if stack.state.to_s.end_with?("failed")
                ui.error("Stack #{ui.color(pstack, :bold)} still exists after polling complete.")
                raise "Failed to successfully destroy stack!"
              end
            rescue Miasma::Error::ApiError::RequestError => error
              # Ignore if stack cannot be reloaded
            end
          else
            ui.error "Stack polling is not available when multiple stack deletion is requested!"
          end
        end
        ui.info "  -> Destroyed SparkleFormation#{plural}: #{ui.color(stacks.join(", "), :bold, :red)}"
      end

      # Cleanup persisted templates if nested stack resources are included
      def nested_stack_cleanup!(stack)
        stack.nested_stacks.each do |n_stack|
          nested_stack_cleanup!(n_stack)
        end
        nest_stacks = stack.template.fetch("Resources", {}).values.find_all do |resource|
          provider.connection.data[:stack_types].include?(resource["Type"])
        end.each do |resource|
          url = resource["Properties"]["TemplateURL"]
          if url && url.is_a?(String)
            _, bucket_name, path = URI.parse(url).path.split("/", 3)
            bucket = provider.connection.api_for(:storage).buckets.get(bucket_name)
            if bucket
              file = bucket.files.get(path)
              if file
                file.destroy
                ui.info "Deleted nested stack template! (Bucket: #{bucket_name} Template: #{path})"
              else
                ui.warn "Failed to locate template file within bucket for deletion! (#{path})"
              end
            else
              ui.warn "Failed to locate bucket containing template file for deletion! (#{bucket_name})"
            end
          end
        end
      end
    end
  end
end