action :run do
  configure
  new_resource.updated_by_last_action(true)
end

def configure
  base_piddir = new_resource.base_piddir

  current_version = if new_resource.version.nil?
                      version
                    else
                      new_resource.version
                    end

  version_hash = RedisioHelper.version_to_hash(current_version)

  # Setup a configuration file and init script for each configuration provided
  new_resource.sentinels.each do |current_instance|
    # Retrieve the default settings hash and the current server setups settings hash.
    current_instance_hash = current_instance.to_hash
    current_defaults_hash = new_resource.sentinel_defaults.to_hash

    # Merge the configuration defaults with the provided array of configurations provided
    current = current_defaults_hash.merge(current_instance_hash)

    recipe_eval do
      sentinel_name = current['name'] || current['port']
      sentinel_name = "sentinel_#{sentinel_name}"
      piddir = "#{base_piddir}/#{sentinel_name}"

      # Create the owner of the redis data directory
      user current['user'] do
        comment 'Redis service account'
        manage_home true
        home current['homedir']
        shell current['shell']
        system current['systemuser']
        uid current['uid'] unless current['uid'].nil?
      end

      # Create the redis configuration directory
      directory current['configdir'] do
        owner 'root'
        group platform_family?('freebsd') ? 'wheel' : 'root'
        mode '0755'
        recursive true
        action :create
      end
      # Create the pid file directory
      directory piddir do
        owner current['user']
        group current['group']
        mode '0755'
        recursive true
        action :create
      end

      unless current['logfile'].nil?
        # Create the log directory if syslog is not being used
        directory ::File.dirname(current['logfile']) do
          owner current['user']
          group current['group']
          mode '0755'
          recursive true
          action :create
          only_if { current['syslogenabled'] != 'yes' && current['logfile'] && current['logfile'] != 'stdout' }
        end

        # Create the log file is syslog is not being used
        file current['logfile'] do
          owner current['user']
          group current['group']
          mode '0644'
          backup false
          action :touch
          only_if { current['logfile'] && current['logfile'] != 'stdout' }
        end
      end

      # <%=@name%> <%=@masterip%> <%=@masterport%> <%= @quorum_count %>
      # <%= "sentinel auth-pass #{@name} #{@authpass}" unless @authpass.nil? %>
      # sentinel down-after-milliseconds <%=@name%> <%=@downaftermil%>
      # sentinel parallel-syncs <%=@name%> <%=@parallelsyncs%>
      # sentinel failover-timeout <%=@name%> <%=@failovertimeout%>

      # convert from old format (preserve compat)
      if !current['masters'] && current['master_ip']
        Chef::Log.warn('You are using a deprecated sentinel format. This will be removed in future versions.')

        # use old key names if newer key names aren't present (e.g. 'foo' || :foo)
        masters = [
          {
            master_name:             current['master_name'] || current[:mastername],
            master_ip:               current['master_ip'] || current[:masterip],
            master_port:             current['master_port'] || current[:masterport],
            quorum_count:            current['quorum_count'] || current[:quorum_count],
            auth_pass:               current['auth-pass'] || current[:authpass],
            down_after_milliseconds: current['down-after-milliseconds'] || current[:downaftermil],
            parallel_syncs:          current['parallel-syncs'] || current[:parallelsyncs],
            failover_timeout:        current['failover-timeout'] || current[:failovertimeout],
          },
        ]
      else
        masters = [current['masters']].flatten
      end

      # Load password for use with requirepass from data bag if needed
      if current['data_bag_name'] && current['data_bag_item'] && current['data_bag_key']
        bag = data_bag_item(current['data_bag_name'], current['data_bag_item'])
        masters.each do |master|
          master['auth_pass'] = bag[current['data_bag_key']]
        end
      end

      # merge in default values to each sentinel hash
      masters_with_defaults = []
      masters.each do |current_sentinel_master|
        default_sentinel_master = new_resource.sentinel_defaults.to_hash
        sentinel_master = default_sentinel_master.merge(current_sentinel_master || {})
        masters_with_defaults << sentinel_master
      end

      # Don't render a template if we're missing these from any sentinel,
      # as these are the minimal settings required to be passed in
      masters_with_defaults.each do |sentinel_instance|
        %w(master_ip master_port quorum_count).each do |param|
          raise "Missing required sentinel parameter #{param} for #{sentinel_instance}" unless sentinel_instance[param]
        end
      end

      # Lay down the configuration files for the current instance
      template "#{current['configdir']}/#{sentinel_name}.conf" do
        source 'sentinel.conf.erb'
        cookbook 'redisio'
        owner current['user']
        group current['group']
        mode '0644'
        action :create
        variables(
          name:                   current['name'],
          piddir:                 piddir,
          version:                version_hash,
          job_control:            node['redisio']['job_control'],
          sentinel_bind:          current['sentinel_bind'],
          sentinel_port:          current['sentinel_port'],
          loglevel:               current['loglevel'],
          logfile:                current['logfile'],
          syslogenabled:          current['syslogenabled'],
          syslogfacility:         current['syslogfacility'],
          masters:                masters_with_defaults,
          announce_ip:            current['announce-ip'],
          announce_port:          current['announce-port'],
          notification_script:    current['notification-script'],
          client_reconfig_script: current['client-reconfig-script']
        )
        not_if { ::File.exist?("#{current['configdir']}/#{sentinel_name}.conf.breadcrumb") }
      end

      file "#{current['configdir']}/#{sentinel_name}.conf.breadcrumb" do
        content 'This file prevents the chef cookbook from overwritting the sentinel config more than once'
        action :create_if_missing
      end

      # Setup init.d file
      bin_path = if node['redisio']['install_dir']
                   ::File.join(node['redisio']['install_dir'], 'bin')
                 else
                   node['redisio']['bin_path']
                 end
      template "/etc/init.d/redis_#{sentinel_name}" do
        source 'sentinel.init.erb'
        cookbook 'redisio'
        owner 'root'
        group 'root'
        mode '0755'
        variables(
          name:      sentinel_name,
          bin_path:  bin_path,
          user:      current['user'],
          configdir: current['configdir'],
          piddir:    piddir,
          platform:  node['platform']
        )
        only_if { node['redisio']['job_control'] == 'initd' }
      end

      template "/etc/init/redis_#{sentinel_name}.conf" do
        source 'sentinel.upstart.conf.erb'
        cookbook 'redisio'
        owner current['user']
        group current['group']
        mode '0644'
        variables(
          name:      sentinel_name,
          bin_path:  bin_path,
          user:      current['user'],
          group:     current['group'],
          configdir: current['configdir'],
          piddir:    piddir
        )
        only_if { node['redisio']['job_control'] == 'upstart' }
      end
      # TODO: fix for freebsd
      template "/usr/local/etc/rc.d/redis_#{sentinel_name}" do
        source 'sentinel.rcinit.erb'
        cookbook 'redisio'
        owner current['user']
        group current['group']
        mode '0755'
        variables(
          name:      sentinel_name,
          bin_path:  bin_path,
          user:      current['user'],
          configdir: current['configdir'],
          piddir:    piddir
        )
        only_if { node['redisio']['job_control'] == 'rcinit' }
      end
    end
  end
  # servers each loop
end

def redis_exists?
  bin_path = if node['redisio']['install_dir']
               ::File.join(node['redisio']['install_dir'], 'bin')
             else
               node['redisio']['bin_path']
             end
  redis_server = ::File.join(bin_path, 'redis-server')
  ::File.exist?(redis_server)
end

def version
  if redis_exists?
    bin_path = if node['redisio']['install_dir']
                 ::File.join(node['redisio']['install_dir'], 'bin')
               else
                 node['redisio']['bin_path']
               end
    redis_server = ::File.join(bin_path, 'redis-server')
    redis_version = Mixlib::ShellOut.new("#{redis_server} -v")
    redis_version.run_command
    version = redis_version.stdout[/version (\d*.\d*.\d*)/, 1] || redis_version.stdout[/v=(\d*.\d*.\d*)/, 1]
    Chef::Log.info("The Redis server version is: #{version}")
    return version.delete("\n")
  end
  nil
end

def load_current_resource
  @current_resource = Chef::Resource.resource_for_node(:redisio_sentinel, node).new(new_resource.name)
  @current_resource.version(version)
  @current_resource
end
