// 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.

//! Row-oriented value-buffer serialization for the `insertRecord(s)` RPC
//! family. Unlike the tablet's column-major layout (spec §3.2), a record
//! interleaves type and value per field: each cell is a 1-byte TSDataType
//! marker followed by its big-endian payload.

use super::tablet::write_binary;
use super::value::Value;

/// Java `SessionUtils.TYPE_NULL` (`-2`): a null cell is this bare marker
/// byte with no payload — the server's `InsertRowNode` reads `-2` as
/// null-without-type.
const TYPE_NULL: u8 = 0xFE;

/// Serializes one record row for `insertRecord`/`insertRecords`/
/// `insertRecordsOfOneDevice`: per value a 1-byte type-code marker plus the
/// big-endian payload (TEXT/STRING/BLOB carry a 4-byte BE length prefix;
/// DATE is i32 `yyyyMMdd`; BOOLEAN is one byte). [`Value::Null`] cells are
/// the bare [`TYPE_NULL`] marker, matching the Java client.
pub fn serialize_record_values(values: &[Value]) -> Vec<u8> {
    let mut buf = Vec::new();
    for value in values {
        match value {
            Value::Null => buf.push(TYPE_NULL),
            other => {
                let code = other.type_code().expect("non-null value carries a type");
                buf.push(code as u8);
                match other {
                    Value::Boolean(b) => buf.push(u8::from(*b)),
                    Value::Int32(v) | Value::Date(v) => buf.extend_from_slice(&v.to_be_bytes()),
                    Value::Int64(v) | Value::Timestamp(v) => {
                        buf.extend_from_slice(&v.to_be_bytes())
                    }
                    Value::Float(v) => buf.extend_from_slice(&v.to_be_bytes()),
                    Value::Double(v) => buf.extend_from_slice(&v.to_be_bytes()),
                    Value::Text(s) | Value::String(s) => write_binary(&mut buf, s.as_bytes()),
                    Value::Blob(b) => write_binary(&mut buf, b),
                    Value::Null => unreachable!("handled above"),
                }
            }
        }
    }
    buf
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn all_types_known_bytes() {
        let values = [
            Value::Boolean(true),
            Value::Int32(7),
            Value::Int64(-2),
            Value::Float(1.5),
            Value::Double(-0.5),
            Value::Text("ab".into()),
            Value::Timestamp(3),
            Value::Date(20260713),
            Value::Blob(vec![0xDE, 0xAD]),
            Value::String("é".into()),
        ];

        let mut expected: Vec<u8> = Vec::new();
        expected.extend_from_slice(&[0x00, 0x01]); // BOOLEAN true
        expected.push(0x01);
        expected.extend_from_slice(&7i32.to_be_bytes());
        expected.push(0x02);
        expected.extend_from_slice(&(-2i64).to_be_bytes());
        expected.push(0x03);
        expected.extend_from_slice(&[0x3F, 0xC0, 0x00, 0x00]); // 1.5f32 IEEE 754 BE
        expected.push(0x04);
        expected.extend_from_slice(&(-0.5f64).to_be_bytes());
        expected.extend_from_slice(&[0x05, 0, 0, 0, 2, b'a', b'b']);
        expected.push(0x08);
        expected.extend_from_slice(&3i64.to_be_bytes());
        expected.push(0x09);
        expected.extend_from_slice(&20260713i32.to_be_bytes()); // yyyyMMdd
        expected.extend_from_slice(&[0x0A, 0, 0, 0, 2, 0xDE, 0xAD]);
        expected.extend_from_slice(&[0x0B, 0, 0, 0, 2, 0xC3, 0xA9]); // "é" UTF-8
        assert_eq!(serialize_record_values(&values), expected);
    }

    #[test]
    fn null_is_bare_type_marker() {
        assert_eq!(serialize_record_values(&[Value::Null]), [0xFE]);
        // Nulls interleave with typed cells without payload bytes.
        let buf = serialize_record_values(&[
            Value::Int32(5),
            Value::Null,
            Value::Boolean(false),
            Value::Null,
        ]);
        assert_eq!(buf, [0x01, 0, 0, 0, 5, 0xFE, 0x00, 0x00, 0xFE]);
    }

    #[test]
    fn empty_row_is_empty_buffer() {
        assert_eq!(serialize_record_values(&[]), Vec::<u8>::new());
    }
}
