require 'json'
require 'tempfile'
require 'open3'
require 'fileutils'
require 'open-uri'

module JamRuby

  # Interact with external python tools to create the JKZ
  class JamTracksManager

    @@log = Logging.logger[JamTracksManager]

    include JamRuby::S3ManagerMixin

    class << self


      def save_jam_track_jkz(user, jam_track, sample_rate=48)
        jam_track_right = jam_track.right_for_user(user)
        raise ArgumentError if jam_track_right.nil?
        save_jam_track_right_jkz(jam_track_right, sample_rate)
      end

      # increment the step, which causes a notification to be sent to the client so it can keep the UI fresh as the packaging step goes on
      def bump_step(jam_track_right, step)
        last_step_at = Time.now
        jam_track_right.current_packaging_step = step
        jam_track_right.last_step_at = Time.now
        JamTrackRight.where(:id => jam_track_right.id).update_all(last_step_at: last_step_at, current_packaging_step: step)
        SubscriptionMessage.jam_track_signing_job_change(jam_track_right)
        step = step + 1
        step
      end

      def save_jam_track_right_jkz(jam_track_right, sample_rate=48)
        jam_track = jam_track_right.jam_track
        jam_track.reload
        py_root = APP_CONFIG.jamtracks_dir
        step = 0
        Dir.mktmpdir do |tmp_dir|
          jam_file_opts=""
          jam_track.jam_track_tracks.each do |jam_track_track|

            next if jam_track_track.track_type == "Master" # master mixes do not go into the JKZ

            # use the jam_track_track ID as the filename.ogg/.wav, because it's important metadata
            nm = jam_track_track.id + File.extname(jam_track_track.url_by_sample_rate(sample_rate))
            track_filename = File.join(tmp_dir, nm)
            track_url = jam_track_track.sign_url(120, sample_rate)
            @@log.info("downloading #{track_url} to #{track_filename}")

            step = bump_step(jam_track_right, step)

            copy_url_to_file(track_url, track_filename)
            part = jam_track_track.track_type == 'Click' ? 'ClickTrack' : jam_track_track.part
            jam_file_opts << " -i #{Shellwords.escape("#{track_filename}+#{part}")}"
          end
          #puts "LS + " + `ls -la '#{tmp_dir}'`
          
          sku=jam_track.id
          title=jam_track.name          
          output_jkz=File.join(tmp_dir, "#{title.parameterize}.jkz")
          py_file = File.join(py_root, "jkcreate.py")
          version = jam_track.version
          @@log.info "Executing python source in #{py_file}, outputting to #{tmp_dir} (#{output_jkz})"

          step = bump_step(jam_track_right, step)

          # From http://stackoverflow.com/questions/690151/getting-output-of-system-calls-in-ruby/5970819#5970819:
          cli = "python #{py_file} -D -k #{sku} -p #{Shellwords.escape(tmp_dir)}/pkey.pem -s #{Shellwords.escape(tmp_dir)}/skey.pem #{jam_file_opts} -o #{Shellwords.escape(output_jkz)} -t #{Shellwords.escape(title)} -V #{Shellwords.escape(version)}"
          Open3.popen3(cli) do |stdin, stdout, stderr, wait_thr|
            pid = wait_thr.pid
            exit_status = wait_thr.value
            err = stderr.read(1000)
            out = stdout.read(1000)
            #puts "stdout: #{out}, stderr: #{err}"
            raise ArgumentError, "Error calling python script: #{err}" if err.present?
            raise ArgumentError, "Error calling python script: #{out}" if out && (out.index("No track files specified") || out.index("Cannot find file"))
            
            #raise ArgumentError, "output_jkz is empty #{output_jkz}" unless File.exists?(output_jkz)
            if sample_rate==48
              jam_track_right.url_48.store!(File.open(output_jkz, "rb"))
            else
              jam_track_right.url_44.store!(File.open(output_jkz, "rb"))
            end

            if sample_rate == 48
              jam_track_right.signed_48 = true
              jam_track_right.private_key_48 = File.read("#{tmp_dir}/skey.pem")
            else
              jam_track_right.signed_44 = true
              jam_track_right.private_key_44 = File.read("#{tmp_dir}/skey.pem")
            end

            jam_track_right.signing_queued_at = nil # if left set, throws off signing_state on subsequent signing attempts
            jam_track_right.downloaded_since_sign = false

            jam_track_right.save!            
          end          
        end # mktmpdir
        jam_track_right
      end # save_jam_track_jkz

      def copy_url_to_file(url, filename)
        uri = URI(url)
        open(filename, 'w+b') do |io|
          Net::HTTP.start(uri.host, uri.port, use_ssl: url.start_with?('https') ? true : false) do |http|
            request = Net::HTTP::Get.new uri
            http.request request do |response|
              response_code = response.code.to_i
              unless response_code >= 200 && response_code <= 299
                @@log.info "Response from server was #{response_code} / #{response.message}"
                raise "bad status code: #{response_code}. body: #{response.body}"
              end
              response.read_body do |chunk|
                io.write chunk
              end
            end
          end
        end
      end # copy_url_to_file

    end # self  
  end # class
end # module
