# frozen_string_literal: true

require 'active_support/core_ext/module/delegation'

module CarrierWave
  module Storage
    class GcloudFile
      GCLOUD_STORAGE_URL = 'https://storage.googleapis.com'

      attr_writer :file
      attr_accessor :uploader, :connection, :path, :file_exists

      delegate :content_disposition, :content_type, :size, to: :file, allow_nil: true

      def initialize(uploader, connection, path)
        @uploader   = uploader
        @connection = connection
        @path       = path
      end

      def file
        @file ||= bucket.file(path)
      end
      alias to_file file

      def attributes
        return unless exists?
        {
          content_type: file.content_type,
          size: file.size,
          updated_at: file.updated_at.to_s,
          etag: file.etag
        }
      end

      def delete
        deleted = file ? file.delete : true
        @file = nil if deleted
        deleted
      end

      def exists?
        !file.nil?
      end

      def extension
        elements = path.split('.')
        elements.last if elements.size > 1
      end

      def filename(options = {})
        CarrierWave::Support::UriFilename.filename(file.url)
      end

      def read
        tmp_file = Tempfile.new(
          CarrierWave::Support::UriFilename.filename(file.name)
        )
        (file.download tmp_file.path, verify: :all).read
      end

      def store(new_file)
        if new_file.is_a?(self.class)
          new_file.copy_to(path)
        else
          @file = bucket.create_file(
            new_file.path,
            path,
            acl: uploader.gcloud_bucket_is_public ? 'publicRead' : nil,
            content_type: new_file.content_type,
            content_disposition: uploader.gcloud_content_disposition
          )
        end
        self
      end

      def copy_to(new_path)
        file.copy(
          new_path,
          acl: uploader.gcloud_bucket_is_public ? 'publicRead' : nil
        )
      end

      def url(options = {})
        uploader.gcloud_bucket_is_public ? public_url : authenticated_url(options)
      end

      def authenticated_url(options = {})
        if uploader.gcloud_authenticated_url_expiration
          options = { expires: uploader.gcloud_authenticated_url_expiration }.merge(options)
        end
        bucket.signed_url(path, **options)
      end

      def public_url
        if uploader.asset_host
          "#{uploader.asset_host}/#{path}"
        else
          "#{GCLOUD_STORAGE_URL}/#{uploader.gcloud_bucket}/#{@path}"
        end
      end

      private

      def bucket
        @bucket ||= connection.bucket(uploader.gcloud_bucket, skip_lookup: true)
      end
    end
  end
end
