# encoding: binary
# typed: strict
# frozen_string_literal: true

module Paseto
  module Protocol
    class Version3
      extend T::Sig
      extend T::Helpers

      include Interface::Version

      sig(:final) { override.params(key: String, nonce: String, payload: String).returns(String) }
      def self.crypt(key:, nonce:, payload:)
        cipher = OpenSSL::Cipher.new('aes-256-ctr')
        cipher.key = key
        cipher.iv = nonce
        cipher.update(payload) + cipher.final
      end

      sig(:final) { override.params(data: String, digest_size: Integer).returns(String) }
      def self.digest(data, digest_size:)
        T.must(OpenSSL::Digest.digest('SHA384', data).byteslice(0, digest_size))
      end

      sig(:final) { override.returns(Integer) }
      def self.digest_bytes
        48
      end

      sig(:final) { override.params(data: String, key: String, digest_size: Integer).returns(String) }
      def self.hmac(data, key:, digest_size:)
        T.must(OpenSSL::HMAC.digest('SHA384', key, data).byteslice(0, digest_size))
      end

      sig(:final) { override.returns(T.class_of(Operations::ID::IDv3)) }
      def self.id
        Operations::ID::IDv3
      end

      sig(:final) do
        override.params(
          password: String,
          salt: String,
          length: Integer,
          parameters: Integer
        ).returns(String)
      end
      def self.kdf(password, salt:, length:, **parameters)
        OpenSSL::KDF.pbkdf2_hmac(
          password,
          salt: salt,
          length: length,
          iterations: T.must(parameters[:iterations]),
          hash: 'SHA384'
        )
      end

      sig(:final) { override.returns(String) }
      def self.paserk_version
        'k3'
      end

      sig(:final) { override.returns(String) }
      def self.pbkd_local_header
        'k3.local-pw'
      end

      sig(:final) { override.returns(String) }
      def self.pbkd_secret_header
        'k3.secret-pw'
      end

      sig(:final) { override.params(password: String).returns(Operations::PBKD::PBKDv3) }
      def self.pbkw(password)
        Operations::PBKD::PBKDv3.new(password)
      end

      sig(:final) { override.params(key: SymmetricKey).returns(Wrappers::PIE::PieV3) }
      def self.pie(key)
        Wrappers::PIE::PieV3.new(key)
      end

      sig(:final) { override.params(key: AsymmetricKey).returns(Operations::PKE::PKEv3) }
      def self.pke(key)
        Operations::PKE::PKEv3.new(key)
      end

      sig(:final) { override.params(size: Integer).returns(String) }
      def self.random(size)
        SecureRandom.random_bytes(size)
      end

      sig(:final) { override.returns(String) }
      def self.version
        'v3'
      end
    end
  end
end