require "db/mongo/models/model_with_provider"
require "db/mongo/models/stack_template/stack_template_factory"
require "providers/exceptions/name_conflict"
require "db/validators/run_list_array"

module Devops
  module Model
    class StackBase

      include ::Mongoid::Document
      include ::Mongoid::Timestamps::Created
      include ::ActiveModel::Validations

      store_in collection: "stacks"

      include ModelWithProviderAccount

      field :_id, as: :id, overwrite: true, type: String
      field :name, type: String
      field :project, type: String
      field :environment, type: String
      field :category, type: String
      field :stack_template, type: String
      field :parameters, type: Hash, default: {}
      field :owner, type: String
      field :run_list, type: Array, default: []
      field :stack_status, type: String
      field :persisting_is_locked, type: Boolean
      field :tags, type: Hash, default: {}

      attr_accessor :events

      validates :id, :project, :environment, :category, :stack_template, :owner, presence: true
      validates :id, uniqueness: true, on: :create
      validates :name, presence: true, allow_nil: true
      validates :run_list, runListArray: {allow_nil: true}

      def to_hash
        attributes.tap { |hash| hash['id'] = hash.delete('_id') }
      end

      def create_stack_in_cloud! out
        begin
          provider_instance.create_stack(self, out)
        rescue ProviderErrors::NameConflict
          raise InvalidRecord.new "Duplicate key error: stack with name '#{id}' already exists in cloud"
        end
      end

      def delete_stack_in_cloud!
        provider_instance.delete_stack(self)
      end

      def sync_status_and_events!
        self.stack_status = provider_instance.stack_details(self)[:stack_status]
        self.events = provider_instance.stack_events(self)
      rescue Fog::AWS::CloudFormation::NotFound
        self.stack_status = 'NOT_FOUND'
      end

      def resources
        provider_instance.stack_resources(self)
      end

      # resource_id is logical
      def resource(resource_id)
        provider_instance.stack_resource(self, resource_id)
      end

      def stack_template_model
        Devops::Model::StackTemplateFactory.get_class(provider).find(stack_template)
      end

      def lock_persisting!
        update_attribute :persisting_is_locked, true
      end

      def unlock_persisting!
        update_attribute :persisting_is_locked, false
      end

      def account_instance
        @account_instance ||= Devops::Model::AwsProviderAccount.find(provider_account)
      end


      class << self

        # attrs should include:
        # - id (String)
        # - environment (String)
        # - stack_template (String)
        # - provider (String)
        # - provider_account (String)
        def create(attrs, out)
          model = new(attrs)
          model.create_stack_in_cloud!(out)
          model.sync_status_and_events!
          model
        end
      end

    end
  end
end
