# Copyright 2023-present ScyllaDB
#
# SPDX-License-Identifier: AGPL-3.0-or-later

###############################################################################
# Tests for various operations on COUNTER columns.
# See also tests for casting involving counter columns in test_cast_data.py
###############################################################################

import pytest
from util import new_test_table, unique_key_int
from cassandra.protocol import InvalidRequest

@pytest.fixture(scope="module")
def table1(cql, test_keyspace):
    with new_test_table(cql, test_keyspace, "p int PRIMARY KEY, i bigint, v int") as table:
        yield table

@pytest.fixture(scope="module")
def table2(cql, test_keyspace):
    with new_test_table(cql, test_keyspace, "p int PRIMARY KEY, c counter") as table:
        yield table

# Test that the function counterasblob() exists and works as expected -
# same as bigintasblob on the same number (a counter is a 64-bit number).
# Reproduces #14742
def test_counter_to_blob(cql, table1, table2):
    p = unique_key_int()
    cql.execute(f'UPDATE {table1} SET i = 1000 WHERE p = {p}')
    cql.execute(f'UPDATE {table2} SET c = c + 1000 WHERE p = {p}')
    expected = b'\x00\x00\x00\x00\x00\x00\x03\xe8'
    assert [(expected,)] == list(cql.execute(f"SELECT bigintasblob(i) FROM {table1} WHERE p={p}"))
    assert [(expected,)] == list(cql.execute(f"SELECT counterasblob(c) FROM {table2} WHERE p={p}"))
    # Although the representation of the counter and bigint types are the
    # same (64-bit), you can't use the wrong "*asblob()" function:
    with pytest.raises(InvalidRequest, match='counterasblob'):
        cql.execute(f"SELECT counterasblob(i) FROM {table1} WHERE p={p}")
    # The opposite order is allowed in Scylla because of #14319, so let's
    # split it into a second test test_counter_to_blob2:
@pytest.mark.xfail(reason="issue #14319")
def test_counter_to_blob2(cql, table1, table2):
    p = unique_key_int()
    cql.execute(f'UPDATE {table2} SET c = c + 1000 WHERE p = {p}')
    # Reproduces #14319:
    with pytest.raises(InvalidRequest, match='bigintasblob'):
        cql.execute(f"SELECT bigintasblob(c) FROM {table2} WHERE p={p}")

# Test that the function blobascounter() exists and works as expected.
# Reproduces #14742
def test_counter_from_blob(cql, table1):
    p = unique_key_int()
    cql.execute(f'UPDATE {table1} SET i = 1000 WHERE p = {p}')
    assert [(1000,)] == list(cql.execute(f"SELECT blobascounter(bigintasblob(i)) FROM {table1} WHERE p={p}"))

# blobascounter() must insist to receive a properly-sized (8-byte) blob.
# If it accepts a shorter blob (e.g., 4 bytes) and returns that to the driver,
# it will confuse the driver (the driver will expect to read 8 bytes for the
# bigint but will get only 4).
# We have test_native_functions.py::test_blobas_wrong_size() that verifies
# that this protection works for the bigint type, but it turns out it also
# needs to be separately enforced for the counter type.
def test_blobascounter_wrong_size(cql, table1):
    p = unique_key_int()
    cql.execute(f'UPDATE {table1} SET v = 1000 WHERE p = {p}')
    with pytest.raises(InvalidRequest, match='blobascounter'):
        cql.execute(f"SELECT blobascounter(intasblob(v)) FROM {table1} WHERE p={p}")
