//! ClickType Core - Type-safe ClickHouse types and traits
//!
//! This crate provides the foundational types, traits, and error handling
//! for the ClickType ecosystem.

#![deny(missing_docs)]
#![allow(clippy::new_without_default)]

pub mod error;
pub mod state;
pub mod traits;
pub mod types;

// Re-exports
pub use error::{Error, ReadError, Result, WriteError};
pub use traits::{ClickHouseType, ClickInsertable, ClickReadable, ClickTable, TypedColumn};
pub use types::*;

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

    #[test]
    fn test_primitives_roundtrip() {
        // Test i64
        let val: i64 = 42;
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = i64::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);

        // Test u64
        let val: u64 = 12345;
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = u64::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);

        // Test f64
        let val: f64 = 3.14159;
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = f64::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);

        // Test bool
        let val = true;
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = bool::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);

        // Test String
        let val = "Hello, ClickHouse!".to_string();
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = String::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);
    }

    #[test]
    fn test_nullable_roundtrip() {
        // Test NULL
        let val: Nullable<i32> = Nullable::null();
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = Nullable::<i32>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert!(decoded.is_null());

        // Test non-NULL
        let val = Nullable::some(42i32);
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = Nullable::<i32>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(decoded.0, Some(42));
    }

    #[test]
    fn test_array_roundtrip() {
        let val = vec![1i32, 2, 3, 4, 5];
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = Vec::<i32>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);

        // Test empty array
        let val: Vec<i32> = vec![];
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = Vec::<i32>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);
    }

    #[test]
    fn test_date_roundtrip() {
        let val = chrono::NaiveDate::from_ymd_opt(2024, 1, 15).unwrap();
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = chrono::NaiveDate::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);
    }

    #[test]
    fn test_datetime64_roundtrip() {
        let dt = chrono::NaiveDateTime::from_timestamp_opt(1705334400, 123_456_789).unwrap();
        let dt64 = DateTime64::<3>::from_naive_datetime(dt);
        let mut buf = Vec::new();
        dt64.write_binary(&mut buf).unwrap();
        let decoded = DateTime64::<3>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(dt64, decoded);

        // Test conversion back to NaiveDateTime
        let decoded_dt = decoded.to_naive_datetime().unwrap();
        // Note: precision loss is expected for millisecond precision
        assert!((dt.and_utc().timestamp() - decoded_dt.and_utc().timestamp()).abs() <= 1);
    }

    #[test]
    fn test_uuid_roundtrip() {
        let val = uuid::Uuid::new_v4();
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = uuid::Uuid::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);
    }

    #[test]
    fn test_low_cardinality() {
        let val = LowCardinality("test".to_string());
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = LowCardinality::<String>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val.0, decoded.0);
    }

    #[test]
    fn test_fixed_size() {
        assert_eq!(i64::fixed_size(), Some(8));
        assert_eq!(u32::fixed_size(), Some(4));
        assert_eq!(bool::fixed_size(), Some(1));
        assert_eq!(String::fixed_size(), None);
        assert_eq!(Vec::<i32>::fixed_size(), None);
    }

    #[test]
    fn test_type_names() {
        assert_eq!(i64::type_name(), "Int64");
        assert_eq!(u32::type_name(), "UInt32");
        assert_eq!(f64::type_name(), "Float64");
        assert_eq!(bool::type_name(), "Bool");
        assert_eq!(String::type_name(), "String");
        assert_eq!(Nullable::<i32>::type_name(), "Nullable(Int32)");
        assert_eq!(Vec::<i32>::type_name(), "Array(Int32)");
        assert_eq!(LowCardinality::<String>::type_name(), "LowCardinality(String)");
    }

    #[test]
    fn test_hashmap_roundtrip() {
        use std::collections::HashMap;

        let mut map = HashMap::new();
        map.insert("key1".to_string(), 100i32);
        map.insert("key2".to_string(), 200i32);
        map.insert("key3".to_string(), 300i32);

        let mut buf = Vec::new();
        map.write_binary(&mut buf).unwrap();
        let decoded = HashMap::<String, i32>::read_binary(&mut Cursor::new(&buf)).unwrap();

        assert_eq!(decoded.len(), 3);
        assert_eq!(decoded.get("key1"), Some(&100));
        assert_eq!(decoded.get("key2"), Some(&200));
        assert_eq!(decoded.get("key3"), Some(&300));
    }

    #[test]
    fn test_empty_hashmap() {
        use std::collections::HashMap;

        let map: HashMap<String, i32> = HashMap::new();
        let mut buf = Vec::new();
        map.write_binary(&mut buf).unwrap();
        let decoded = HashMap::<String, i32>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(decoded.len(), 0);
    }

    #[test]
    fn test_nested_nullable() {
        let val: Nullable<Nullable<i32>> = Nullable::some(Nullable::some(42));
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = Nullable::<Nullable<i32>>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(decoded.0.unwrap().0, Some(42));
    }

    #[test]
    fn test_array_of_strings() {
        let val = vec!["hello".to_string(), "world".to_string(), "test".to_string()];
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = Vec::<String>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);
    }

    #[test]
    fn test_nested_arrays() {
        let val = vec![
            vec![1i32, 2, 3],
            vec![4, 5],
            vec![6, 7, 8, 9],
        ];
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = Vec::<Vec<i32>>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);
    }

    #[test]
    fn test_datetime_roundtrip() {
        let dt = chrono::NaiveDateTime::from_timestamp_opt(1705334400, 0).unwrap();
        let mut buf = Vec::new();
        dt.write_binary(&mut buf).unwrap();
        let decoded = chrono::NaiveDateTime::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(dt.and_utc().timestamp(), decoded.and_utc().timestamp());
    }

    #[test]
    fn test_all_integer_types() {
        // Test all integer types for completeness
        let i8_val: i8 = -42;
        let mut buf = Vec::new();
        i8_val.write_binary(&mut buf).unwrap();
        let decoded = i8::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(i8_val, decoded);

        let u8_val: u8 = 255;
        let mut buf = Vec::new();
        u8_val.write_binary(&mut buf).unwrap();
        let decoded = u8::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(u8_val, decoded);

        let i16_val: i16 = -1000;
        let mut buf = Vec::new();
        i16_val.write_binary(&mut buf).unwrap();
        let decoded = i16::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(i16_val, decoded);

        let u16_val: u16 = 65535;
        let mut buf = Vec::new();
        u16_val.write_binary(&mut buf).unwrap();
        let decoded = u16::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(u16_val, decoded);

        let i32_val: i32 = -100000;
        let mut buf = Vec::new();
        i32_val.write_binary(&mut buf).unwrap();
        let decoded = i32::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(i32_val, decoded);

        let u32_val: u32 = 4294967295;
        let mut buf = Vec::new();
        u32_val.write_binary(&mut buf).unwrap();
        let decoded = u32::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(u32_val, decoded);
    }

    #[test]
    fn test_large_integers() {
        let i128_val: i128 = i128::MAX;
        let mut buf = Vec::new();
        i128_val.write_binary(&mut buf).unwrap();
        let decoded = i128::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(i128_val, decoded);

        let u128_val: u128 = u128::MAX;
        let mut buf = Vec::new();
        u128_val.write_binary(&mut buf).unwrap();
        let decoded = u128::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(u128_val, decoded);
    }

    #[test]
    fn test_float_types() {
        let f32_val: f32 = 3.14159;
        let mut buf = Vec::new();
        f32_val.write_binary(&mut buf).unwrap();
        let decoded = f32::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(f32_val, decoded);

        // Test special float values
        let nan_val = f64::NAN;
        let mut buf = Vec::new();
        nan_val.write_binary(&mut buf).unwrap();
        let decoded = f64::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert!(decoded.is_nan());

        let inf_val = f64::INFINITY;
        let mut buf = Vec::new();
        inf_val.write_binary(&mut buf).unwrap();
        let decoded = f64::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert!(decoded.is_infinite() && decoded.is_sign_positive());
    }

    #[test]
    fn test_string_with_special_chars() {
        let val = "Hello\nWorld\t🦀".to_string();
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = String::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);
    }

    #[test]
    fn test_empty_string() {
        let val = String::new();
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = String::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);
    }

    #[test]
    fn test_nullable_conversions() {
        // Test From<Option<T>>
        let opt_val: Option<i32> = Some(42);
        let nullable: Nullable<i32> = opt_val.into();
        assert_eq!(nullable.0, Some(42));

        // Test From<T>
        let val: i32 = 100;
        let nullable: Nullable<i32> = val.into();
        assert_eq!(nullable.0, Some(100));
    }

    #[test]
    fn test_low_cardinality_conversion() {
        let val = "test".to_string();
        let lc: LowCardinality<String> = val.clone().into();
        assert_eq!(lc.0, val);
    }

    #[test]
    fn test_datetime64_precision() {
        // Test different precision levels
        let dt = chrono::NaiveDateTime::from_timestamp_opt(1705334400, 123_456_789).unwrap();

        // Precision 0 (seconds)
        let dt64_0 = DateTime64::<0>::from_naive_datetime(dt);
        let mut buf = Vec::new();
        dt64_0.write_binary(&mut buf).unwrap();
        let decoded = DateTime64::<0>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(dt64_0, decoded);

        // Precision 6 (microseconds)
        let dt64_6 = DateTime64::<6>::from_naive_datetime(dt);
        let mut buf = Vec::new();
        dt64_6.write_binary(&mut buf).unwrap();
        let decoded = DateTime64::<6>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(dt64_6, decoded);

        // Precision 9 (nanoseconds)
        let dt64_9 = DateTime64::<9>::from_naive_datetime(dt);
        let mut buf = Vec::new();
        dt64_9.write_binary(&mut buf).unwrap();
        let decoded = DateTime64::<9>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(dt64_9, decoded);
    }

    #[test]
    fn test_read_error_unexpected_eof() {
        // Try to read i64 from empty buffer
        let buf: Vec<u8> = vec![];
        let result = i64::read_binary(&mut Cursor::new(&buf));
        assert!(result.is_err());
        match result {
            Err(ReadError::UnexpectedEof) => {},
            _ => panic!("Expected UnexpectedEof error"),
        }
    }

    #[test]
    fn test_read_error_invalid_utf8() {
        // Create a string with invalid UTF-8
        let mut buf = Vec::new();
        // Write length
        buf.push(4); // LEB128 for length 4
        // Write invalid UTF-8 sequence
        buf.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]);

        let result = String::read_binary(&mut Cursor::new(&buf));
        assert!(result.is_err());
        match result {
            Err(ReadError::InvalidFormat(_)) => {},
            _ => panic!("Expected InvalidFormat error"),
        }
    }

    #[test]
    fn test_sql_literals() {
        assert_eq!(42i64.to_sql_literal(), "42");
        assert_eq!("test".to_string().to_sql_literal(), "'test'");
        assert_eq!("O'Brien".to_string().to_sql_literal(), "'O\\'Brien'");

        let date = chrono::NaiveDate::from_ymd_opt(2024, 1, 15).unwrap();
        assert_eq!(date.to_sql_literal(), "'2024-01-15'");

        let uuid = uuid::Uuid::nil();
        assert!(uuid.to_sql_literal().contains("00000000-0000-0000-0000-000000000000"));
    }

    #[test]
    fn test_is_nullable_trait() {
        assert!(!i64::is_nullable());
        assert!(!String::is_nullable());
        assert!(Nullable::<i32>::is_nullable());
        assert!(Nullable::<String>::is_nullable());
    }

    #[test]
    fn test_large_array() {
        // Test with a larger array to ensure LEB128 encoding works correctly
        let val: Vec<i32> = (0..1000).collect();
        let mut buf = Vec::new();
        val.write_binary(&mut buf).unwrap();
        let decoded = Vec::<i32>::read_binary(&mut Cursor::new(&buf)).unwrap();
        assert_eq!(val, decoded);
    }
}
