# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

"""Java RowCompactedSerializer keys used by composite BTree indexes."""

import math
import struct

from pypaimon.data.timestamp import Timestamp
from pypaimon.execution.python.globalindex.key_serializer import (
    KeySerializer, create_serializer, _read_var_len_int, _write_var_len_int,
    _parse_precision,
)


class CompositeKeySerializer(KeySerializer):
    def __init__(self, fields):
        self._types = [field.type.type.upper() for field in fields]
        self._serializers = [create_serializer(field.type) for field in fields]
        self._comparators = [
            _java_float_compare if type_name in ('FLOAT', 'DOUBLE')
            else serializer.create_comparator()
            for type_name, serializer in zip(self._types, self._serializers)
        ]
        self._header_size = (len(fields) + 15) // 8

    def serialize(self, key):
        if len(key) != len(self._serializers):
            raise ValueError("Wrong composite key arity")
        header = bytearray(self._header_size)
        values = bytearray()
        for index, (value, serializer, type_name) in enumerate(
                zip(key, self._serializers, self._types)):
            if value is None:
                header[(index + 8) // 8] |= 1 << ((index + 8) % 8)
                continue
            if type_name == 'FLOAT' and math.isnan(float(value)):
                encoded = struct.pack('<I', 0x7fc00000)
            elif type_name == 'DOUBLE' and math.isnan(float(value)):
                encoded = struct.pack('<Q', 0x7ff8000000000000)
            else:
                encoded = serializer.serialize(value)
            if _variable_length(type_name):
                values.extend(_write_var_len_int(len(encoded)))
            values.extend(encoded)
        return bytes(header + values)

    def deserialize(self, data):
        if len(data) < self._header_size:
            raise ValueError("Truncated composite key")
        position = self._header_size
        result = []
        for index, (serializer, type_name) in enumerate(
                zip(self._serializers, self._types)):
            if data[(index + 8) // 8] & (1 << ((index + 8) % 8)):
                result.append(None)
                continue
            if _variable_length(type_name):
                length, position = _read_var_len_int(data, position)
            else:
                length = _fixed_length(type_name)
                if type_name.startswith('TIMESTAMP') and _parse_precision(
                        type_name, 6) > 3:
                    _, end = _read_var_len_int(data, position + 8)
                    length = end - position
            end = position + length
            if end > len(data):
                raise ValueError("Truncated composite key value")
            encoded = data[position:end]
            if type_name.startswith('TIMESTAMP'):
                milliseconds = struct.unpack('<q', encoded[:8])[0]
                nanos = (_read_var_len_int(encoded, 8)[0]
                         if len(encoded) > 8 else 0)
                result.append(Timestamp.from_epoch_millis(milliseconds, nanos))
            elif type_name == 'DATE' or (type_name.startswith('TIME')
                                         and not type_name.startswith('TIMESTAMP')):
                result.append(struct.unpack('<i', encoded)[0])
            else:
                result.append(serializer.deserialize(encoded))
            position = end
        if position != len(data):
            raise ValueError("Trailing composite key bytes")
        return tuple(result)

    def create_comparator(self):
        def compare(left, right):
            for a, b, comparator in zip(left, right, self._comparators):
                difference = compare_nullable(a, b, comparator)
                if difference:
                    return difference
            return 0
        return compare


def _variable_length(type_name):
    return (type_name.startswith(('CHAR', 'VARCHAR', 'STRING'))
            or type_name.startswith(('DECIMAL', 'NUMERIC'))
            and _decimal_precision(type_name) > 18)


def _decimal_precision(type_name):
    from pypaimon.execution.python.globalindex.key_serializer import _parse_decimal_params
    return _parse_decimal_params(type_name)[0]


def _fixed_length(type_name):
    if type_name in ('BOOLEAN', 'TINYINT'):
        return 1
    if type_name == 'SMALLINT':
        return 2
    if type_name in ('INT', 'INTEGER', 'DATE', 'FLOAT') or (
            type_name.startswith('TIME') and not type_name.startswith('TIMESTAMP')):
        return 4
    if type_name in ('BIGINT', 'DOUBLE') or type_name.startswith(('DECIMAL', 'NUMERIC')):
        return 8
    if type_name.startswith('TIMESTAMP'):
        # The caller handles the optional trailing varint separately.
        return 8
    raise ValueError("Unsupported composite key type: %s" % type_name)


def compare_nullable(left, right, comparator):
    if left is None:
        return 0 if right is None else -1
    if right is None:
        return 1
    return comparator(left, right)


def _java_float_compare(left, right):
    left, right = float(left), float(right)
    if math.isnan(left):
        return 0 if math.isnan(right) else 1
    if math.isnan(right):
        return -1
    if left == right == 0:
        return (math.copysign(1, left) > math.copysign(1, right)) - (
            math.copysign(1, left) < math.copysign(1, right))
    return (left > right) - (left < right)
