require_relative 'configuration_management/chef'

module Devops
  module Model
    class Category

      include ActiveModel::Validations

      attr_accessor :id, :provider, :cm_tool

      MAX_LEN = 100
      ID_REGEX = /\A[\w\-\.]{1,#{MAX_LEN}}\z/

#        validates_presence_of :id, message: "'id' is undefined"
      validates_length_of :id, minimum: 1, maximum: MAX_LEN
      validates_format_of :id, with: ID_REGEX, message: "invalid id, it should contains 'a-zA-Z0-9-.' symbols"

#        validates_presence_of :provider, message: "'provider' is undefined"
#        validates_presence_of :cm_tool, message: "'cm_tool' is undefined"

      def initialize hash
        raise InvalidRecord.new("Parameter 'id' is not a string") unless hash["id"].is_a?(String)
        raise InvalidRecord.new("Parameter 'provider' is not an object") unless hash["provider"].is_a?(Hash)
        raise InvalidRecord.new("Parameter 'cm_tool' is not an object") unless hash["cm_tool"].is_a?(Hash)
        self.id = hash["id"]
        self.provider = Provider.create_category_provider(hash["provider"])
        self.cm_tool = ConfigurationManagement::Chef.new(hash["cm_tool"])
      end

      def to_hash
        {
          "id" => self.id,
          "provider" => self.provider.to_hash,
          "cm_tool" => self.cm_tool.to_hash
        }
      end

      def validate!
        raise Devops::Exception::ValidationError.create_from_messages(self.errors.messages) unless self.valid?
      end

      def create_role(project_id, env_id)
        return {} if cm_tool.use_json_file?
        knife = knife_instance(project_id, env_id)
        create_roles_unless_exist(project_id, env_id, knife)
      end

      def knife_instance(project_id, env_id)
        knife = KnifeFactory.instance(self.cm_tool.chef_env)
        if knife.nil?
          msg = "Unknown chef_env '#{cm_tool.chef_env}' for project '#{project_id}/#{env_id}/#{id}'"
          DevopsLogger.logger.error msg
          raise msg
        end
        knife
      end

      def self.present_created_roles(roles)
        return "error in creating roles" unless roles
        info = ''
        info += "Project roles '#{roles[:new].join("', '")}' have been automaticaly created" unless roles[:new].nil?
        info += " Project roles '#{roles[:exist].join("', '")}' weren't created because they exist" unless roles[:exist].nil?
        info += " Project roles '#{roles[:error].join("', '")}' weren't created because of internal error" unless roles[:error].nil?
        info
      end

      private

      def create_roles_unless_exist(project_id, env_id, knife)
        info = {}
        begin
          role_name = knife.role_name(project_id, env_id, self.id)
          if fetch_roles(knife).include?(role_name)
            info[:exist] = [role_name]
          else
            knife.create_role role_name, project_id, env_id
            info[:new] = [role_name]
            DevopsLogger.logger.info "Role '#{role_name}' created"
          end
          self.run_list << "role[#{role_name}]"
        rescue => er
          info[:error] = [role_name]
          DevopsLogger.logger.error "Role '#{role_name}' can not be created: #{er.message}"
        end
        info
      end

      def fetch_roles(knife)
        roles = knife.roles
        unless roles
          msg = "Can't get roles list from chef env '#{cm_tool.chef_env}'"
          DevopsLogger.logger.error msg
          raise msg
        end
        roles
      end

    end
  end
end

