require 'aws-sdk-s3'
require 'net/http'

module Attachments
  class HostedImage < Service::Base
    attributes :filename, :s3_url
    validates :filename, presence: true

    class AlreadyExistsError < ArgumentError
    end

    def save
      return false unless valid?
      begin
        self.s3_url = self.class.get_s3_url(filename)
      rescue ArgumentError => ae
        self.errors = "failed to get presigned s3 url. err: #{ae.message}"
        return false
      end
      true
    end

    def cdn_url
      [Settings.attachments.cdn_prefix, Settings.attachments.key_prefix, filename].join("/")
    end

    class << self

      def s3_client
        @s3_client ||= Aws::S3::Client.new(
          region: Settings.attachments.region
        )
      end

      def bucket_name
        Settings.attachments.s3_bucket
      end

      def key_name(filename)
        "#{Settings.attachments.key_prefix}/#{filename}"
      end

      def object_exist(filename)
        s3 = Aws::S3::Resource.new(client: self.s3_client)

        bucket = s3.bucket(self.bucket_name)
        bucket.object(key_name(filename)).exists?
      end

      def get_s3_url(filename)
        if self.object_exist(filename)
          raise AlreadyExistsError, "attachment #{filename} already exists."
        end

        signer = Aws::S3::Presigner.new(client: self.s3_client)

        signer.presigned_url(
          :put_object,
          bucket: self.bucket_name,
          key: self.key_name(filename),
          content_type: "image/png",
          secure: true,
          expires_in: 900,
          acl: 'public-read'
        )
      end

    end
  end
end
