# frozen_string_literal: true

require_relative "../abstract_unit"
require_relative "message_metadata_tests"

class MessageVerifierMetadataTest < ActiveSupport::TestCase
  include MessageMetadataTests

  test "#verify raises when :purpose does not match" do
    each_scenario do |data, verifier|
      assert_equal data, verifier.verify(verifier.generate(data, purpose: "x"), purpose: "x")

      assert_raises ActiveSupport::MessageVerifier::InvalidSignature do
        verifier.verify(verifier.generate(data, purpose: "x"), purpose: "y")
      end

      assert_raises ActiveSupport::MessageVerifier::InvalidSignature do
        verifier.verify(verifier.generate(data), purpose: "y")
      end

      assert_raises ActiveSupport::MessageVerifier::InvalidSignature do
        verifier.verify(verifier.generate(data, purpose: "x"))
      end
    end
  end

  test "#verify raises when message is expired via :expires_at" do
    freeze_time do
      each_scenario do |data, verifier|
        message = verifier.generate(data, expires_at: 1.second.from_now)

        travel 0.5.seconds, with_usec: true
        assert_equal data, verifier.verify(message)

        travel 0.5.seconds, with_usec: true
        assert_raises ActiveSupport::MessageVerifier::InvalidSignature do
          verifier.verify(message)
        end
      end
    end
  end

  test "#verify raises when message is expired via :expires_in" do
    freeze_time do
      each_scenario do |data, verifier|
        message = verifier.generate(data, expires_in: 1.second)

        travel 0.5.seconds, with_usec: true
        assert_equal data, verifier.verify(message)

        travel 0.5.seconds, with_usec: true
        assert_raises ActiveSupport::MessageVerifier::InvalidSignature do
          verifier.verify(message)
        end
      end
    end
  end

  test "messages are readable by legacy versions when use_message_serializer_for_metadata = false" do
    # Message generated by Rails 7.0 using:
    #
    #   verifier = ActiveSupport::MessageVerifier.new("secret", serializer: JSON)
    #   legacy_message = verifier.generate("legacy", purpose: "test", expires_at: Time.utc(3000))
    #
    legacy_message = "eyJfcmFpbHMiOnsibWVzc2FnZSI6IklteGxaMkZqZVNJPSIsImV4cCI6IjMwMDAtMDEtMDFUMDA6MDA6MDAuMDAwWiIsInB1ciI6InRlc3QifX0=--81b11c317dba91cedd86ab79b7d7e68de8d290b3"

    verifier = ActiveSupport::MessageVerifier.new("secret", serializer: JSON)

    using_message_serializer_for_metadata(false) do
      assert_equal legacy_message, verifier.generate("legacy", purpose: "test", expires_at: Time.utc(3000))
    end
  end

  test "messages are readable by legacy versions when force_legacy_metadata_serializer is true" do
    # Message generated by Rails 7.0 using:
    #
    #   verifier = ActiveSupport::MessageVerifier.new("secret", serializer: JSON)
    #   legacy_message = verifier.generate("legacy", purpose: "test", expires_at: Time.utc(3000))
    #
    legacy_message = "eyJfcmFpbHMiOnsibWVzc2FnZSI6IklteGxaMkZqZVNJPSIsImV4cCI6IjMwMDAtMDEtMDFUMDA6MDA6MDAuMDAwWiIsInB1ciI6InRlc3QifX0=--81b11c317dba91cedd86ab79b7d7e68de8d290b3"

    using_message_serializer_for_metadata(true) do
      verifier = ActiveSupport::MessageVerifier.new("secret", serializer: JSON, force_legacy_metadata_serializer: true)

      assert_equal legacy_message, verifier.generate("legacy", purpose: "test", expires_at: Time.utc(3000))
    end
  end

  test "messages keep the old format when use_message_serializer_for_metadata is false" do
    # Message generated by Rails 7.0 using:
    #
    #   verifier = ActiveSupport::MessageVerifier.new("secret", serializer: JSON)
    #   legacy_message = verifier.generate("legacy", purpose: "test")
    legacy_message = "eyJfcmFpbHMiOnsibWVzc2FnZSI6IklteGxaMkZqZVNJPSIsImV4cCI6bnVsbCwicHVyIjoidGVzdCJ9fQ==--53b1fc02f5b89b2da8c6ce94efa95f5cb656d975"

    verifier = ActiveSupport::MessageVerifier.new("secret", serializer: JSON)

    using_message_serializer_for_metadata(false) do
      assert_equal legacy_message, verifier.generate("legacy", purpose: "test")
    end
  end

  private
    def make_codec(**options)
      ActiveSupport::MessageVerifier.new("secret", **options)
    end

    def encode(data, verifier, **options)
      verifier.generate(data, **options)
    end

    def decode(message, verifier, **options)
      verifier.verified(message, **options)
    end
end
