require "open-uri"
require "aws-sdk-s3"

module Recordings
  class Storage
    class Error < StandardError; end

    def initialize
      @backend = MatchLiveTv.replay_storage_local? ? LocalBackend.new : S3Backend.new
    end

    def upload(local_path:, key:, content_type: "video/mp4")
      @backend.upload(local_path: local_path, key: key, content_type: content_type)
    end

      def delete(key:)
        @backend.delete(key: key)
      end

      def download_to_temp(key:)
        local = local_path_for_key(key)
        return local if local && File.exist?(local)

        url = presigned_get_url(key: key, expires_in: 600)
        raise Error, "Impossibile scaricare file dallo storage" if url.blank?

        dest = File.join(Dir.tmpdir, "replay-dl-#{SecureRandom.hex(8)}.mp4")
        URI.open(url) do |remote|
          File.binwrite(dest, remote.read)
        end
        dest
      end

    def presigned_get_url(key:, expires_in: MatchLiveTv.replay_presigned_url_ttl_seconds)
      @backend.presigned_get_url(key: key, expires_in: expires_in)
    end

    def local_path_for_key(key)
      @backend.local_path_for_key(key)
    end

    def backend_name
      @backend.name
    end

    class LocalBackend
      def name
        "local"
      end

      def upload(local_path:, key:, content_type:)
        dest = local_path_for_key(key)
        FileUtils.mkdir_p(File.dirname(dest))
        FileUtils.cp(local_path, dest)
        File.size(dest)
      end

      def delete(key:)
        path = local_path_for_key(key)
        FileUtils.rm_f(path)
        true
      end

      def presigned_get_url(key:, expires_in:)
        nil
      end

      def local_path_for_key(key)
        File.join(MatchLiveTv.recordings_local_path, "replays", key)
      end
    end

    class S3Backend
      def name
        "s3"
      end

      def upload(local_path:, key:, content_type:)
        client.put_object(
          bucket: MatchLiveTv.replay_storage_bucket,
          key: key,
          body: File.open(local_path, "rb"),
          content_type: content_type
        )
        File.size(local_path)
      end

      def delete(key:)
        client.delete_object(bucket: MatchLiveTv.replay_storage_bucket, key: key)
        true
      rescue Aws::S3::Errors::ServiceError => e
        raise Error, e.message
      end

      def presigned_get_url(key:, expires_in:)
        signer = Aws::S3::Presigner.new(client: client)
        signer.presigned_url(
          :get_object,
          bucket: MatchLiveTv.replay_storage_bucket,
          key: key,
          expires_in: expires_in
        )
      end

      def local_path_for_key(_key)
        nil
      end

      private

      def client
        @client ||= Aws::S3::Client.new(
          access_key_id: MatchLiveTv.replay_storage_access_key_id,
          secret_access_key: MatchLiveTv.replay_storage_secret_access_key,
          endpoint: MatchLiveTv.replay_storage_endpoint,
          region: MatchLiveTv.replay_storage_region,
          force_path_style: MatchLiveTv.replay_storage_force_path_style?,
          response_checksum_validation: "WHEN_REQUIRED"
        )
      end
    end
  end
end
