// This code is automatically generated by Senax and is always overwritten.

use chrono::{DateTime, NaiveDate, NaiveDateTime, NaiveTime};
use rust_decimal::Decimal;
use senax_common::cache::calc_mem_size;
use senax_encoder::{Decode, Encode, Pack, Unpack};
use serde_json::Value;
use sqlx::query::Query;
use std::convert::TryFrom;

use crate::connection::{DbArguments, DbType};

#[derive(Default, sqlx::FromRow, senax_macros::SqlCol)]
pub struct Count {
    #[sql(query = "count(*)")]
    pub c: i64,
}

#[derive(Default, sqlx::FromRow, senax_macros::SqlCol)]
pub struct Exists {
    #[sql(query = "1")]
    pub exists: i64,
}

#[derive(Debug, Clone, Copy, Default, PartialEq)]
pub enum TrashMode {
    #[default]
    Not,
    With,
    Only,
}

pub trait Size {
    fn _size(&self) -> usize;
}

impl Size for String {
    fn _size(&self) -> usize {
        calc_mem_size(self.capacity()) + std::mem::size_of::<usize>() * 4
    }
}

impl Size for Vec<u8> {
    fn _size(&self) -> usize {
        calc_mem_size(self.capacity()) + std::mem::size_of::<usize>() * 4
    }
}

impl Size for Vec<u32> {
    fn _size(&self) -> usize {
        calc_mem_size(self.capacity() * std::mem::size_of::<u32>())
            + std::mem::size_of::<usize>() * 4
    }
}

impl Size for Vec<u64> {
    fn _size(&self) -> usize {
        calc_mem_size(self.capacity() * std::mem::size_of::<u64>())
            + std::mem::size_of::<usize>() * 4
    }
}

impl Size for Vec<String> {
    fn _size(&self) -> usize {
        calc_mem_size(self.capacity() * std::mem::size_of::<usize>())
            + std::mem::size_of::<usize>() * 2
            + self.iter().fold(0, |i, v| {
                i + v.capacity() + std::mem::size_of::<usize>() * 2
            })
    }
}

pub trait Updater {
    fn is_new(&self) -> bool;
    fn has_been_deleted(&self) -> bool;
    fn mark_for_delete(&mut self);
    fn unmark_for_delete(&mut self);
    fn will_be_deleted(&self) -> bool;
    fn mark_for_upsert(&mut self);
    fn is_updated(&self) -> bool;
    // fn overwrite_except_skip(&mut self, updater: Self);
    // fn overwrite_only_set(&mut self, updater: Self);
    // fn overwrite_with(&mut self, updater: Self, set_only: bool);
}

#[async_trait::async_trait]
pub trait UpdaterForInner {
    fn __validate(&self) -> anyhow::Result<()>;
    async fn __set_default_value(&mut self, conn: &mut crate::DbConn) -> anyhow::Result<()>;
    fn __set_overwrite_extra_value(&mut self, conn: &mut crate::DbConn);
}

#[derive(Clone, Debug)]
pub enum BindValue {
    Bool(Option<bool>),
    Enum(Option<i64>),
    Number(Option<Decimal>),
    String(Option<String>),
    UtcDateTime(Option<DateTime<chrono::Utc>>),
    LocalDateTime(Option<DateTime<chrono::Local>>),
    NaiveDateTime(Option<NaiveDateTime>),
    Date(Option<NaiveDate>),
    Time(Option<NaiveTime>),
    Blob(Option<Vec<u8>>),
    Json(Option<Value>),
    Uuid(Option<uuid::@{ config.db_type_switch("fmt::Hyphenated", "Uuid") }@>),
    BinaryUuid(Option<uuid::Uuid>),
}

impl BindValue {
    pub fn bind(self, query: Query<DbType, DbArguments>) -> Query<DbType, DbArguments> {
        log::debug!(target: "db_@{ db|snake }@::misc", "bind: {:?}", &self);
        match self {
            BindValue::Bool(v) => query.bind(v),
            BindValue::Enum(v) => query.bind(v),
            BindValue::Number(v) => query.bind(v),
            BindValue::String(v) => query.bind(v),
            BindValue::UtcDateTime(v) => query.bind(v),
            BindValue::LocalDateTime(v) => query.bind(v),
            BindValue::NaiveDateTime(v) => query.bind(v),
            BindValue::Date(v) => query.bind(v),
            BindValue::Time(v) => query.bind(v),
            BindValue::Blob(v) => query.bind(v),
            BindValue::Json(v) => query.bind(v),
            BindValue::Uuid(v) => query.bind(v),
            BindValue::BinaryUuid(v) => query.bind(v),
        }
    }
}

macro_rules! impl_bind_value {
    ($T:ty, $U:ident) => {
        impl core::convert::From<$T> for BindValue {
            fn from(t: $T) -> Self {
                Self::$U(Some(t.into()))
            }
        }
        impl core::convert::From<Option<$T>> for BindValue {
            fn from(t: Option<$T>) -> Self {
                Self::$U(t.map(|v| v.into()))
            }
        }
    };
}
impl_bind_value!(bool, Bool);
impl_bind_value!(String, String);
impl_bind_value!(DateTime<chrono::Utc>, UtcDateTime);
impl_bind_value!(DateTime<chrono::Local>, LocalDateTime);
impl_bind_value!(NaiveDateTime, NaiveDateTime);
impl_bind_value!(NaiveDate, Date);
impl_bind_value!(NaiveTime, Time);
impl_bind_value!(Vec<u8>, Blob);
impl_bind_value!(Value, Json);
impl_bind_value!(uuid::Uuid, Uuid);

macro_rules! impl_decimal {
    ($T:ty) => {
        impl core::convert::From<$T> for BindValue {
            fn from(t: $T) -> Self {
                Self::Number(Some(Decimal::from(t)))
            }
        }
        impl core::convert::From<Option<$T>> for BindValue {
            fn from(t: Option<$T>) -> Self {
                Self::Number(t.map(|v| Decimal::from(v)))
            }
        }
    };
}

macro_rules! impl_try_decimal {
    ($T:ty) => {
        impl core::convert::From<$T> for BindValue {
            fn from(t: $T) -> Self {
                Self::Number(Some(Decimal::try_from(t).unwrap()))
            }
        }
        impl core::convert::From<Option<$T>> for BindValue {
            fn from(t: Option<$T>) -> Self {
                Self::Number(t.map(|v| Decimal::try_from(v).unwrap()))
            }
        }
    };
}

impl_decimal!(isize);
impl_decimal!(i8);
impl_decimal!(i16);
impl_decimal!(i32);
impl_decimal!(i64);
impl_decimal!(usize);
impl_decimal!(u8);
impl_decimal!(u16);
impl_decimal!(u32);
impl_decimal!(u64);
impl_decimal!(i128);
impl_decimal!(u128);
impl_decimal!(Decimal);
impl_try_decimal!(f32);
impl_try_decimal!(f64);

#[derive(serde::Serialize, Decode, Encode, Pack, Unpack, Clone, Default)]
#[cfg_attr(all(debug_assertions, not(feature = "production_mode")), senax(disable_pack, disable_encode))]
pub struct JsonRawValue(std::sync::Arc<Box<serde_json::value::RawValue>>);
impl TryFrom<String> for JsonRawValue {
    type Error = Box<dyn std::error::Error + Send + Sync>;
    fn try_from(value: String) -> Result<Self, Self::Error> {
        Ok(Self(serde_json::value::RawValue::from_string(value)?.into()))
    }
}
impl PartialEq for JsonRawValue {
    fn eq(&self, other: &Self) -> bool {
        self.0.get() == other.0.get()
    }
}
impl From<&JsonRawValue> for String {
    fn from(value: &JsonRawValue) -> Self {
        value.0.get().to_string()
    }
}
impl Size for JsonRawValue {
    fn _size(&self) -> usize {
        calc_mem_size(self.0.get().len()) + std::mem::size_of::<usize>() * 4
    }
}
impl std::fmt::Debug for JsonRawValue {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let s: String = self.into();
        write!(f, "{}", s)
    }
}
impl JsonRawValue {
    pub fn to_raw_value(&self) -> std::sync::Arc<Box<serde_json::value::RawValue>> {
        std::sync::Arc::clone(&self.0)
    }
}
impl AsRef<serde_json::value::RawValue> for JsonRawValue {
    fn as_ref(&self) -> &serde_json::value::RawValue {
        &self.0
    }
}
pub trait ToJsonRawValue {
    fn _to_json_raw_value(&self) -> anyhow::Result<JsonRawValue>;
}

impl<T> ToJsonRawValue for T
where
    T: serde::Serialize,
{
    fn _to_json_raw_value(&self) -> anyhow::Result<JsonRawValue> {
        let v = serde_json::to_string(self)?;
        Ok(JsonRawValue(serde_json::value::RawValue::from_string(v)?.into()))
    }
}

pub mod arc_bytes {
    use serde::{Deserialize, Deserializer, Serializer};
    use serde_bytes::ByteBuf;
    use std::sync::Arc;

    pub fn serialize<S>(data: &Arc<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_bytes(data.as_slice())
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Arc<Vec<u8>>, D::Error>
    where
        D: Deserializer<'de>,
    {
        let buf = ByteBuf::deserialize(deserializer)?;
        Ok(Arc::new(buf.into_vec()))
    }
}
pub mod option_arc_bytes {
    use serde::{Deserialize, Deserializer, Serializer};
    use serde_bytes::ByteBuf;
    use std::sync::Arc;

    pub fn serialize<S>(data: &Option<Arc<Vec<u8>>>, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        match data {
            Some(value) => serializer.serialize_bytes(value.as_slice()),
            None => serializer.serialize_none(),
        }
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Arc<Vec<u8>>>, D::Error>
    where
        D: Deserializer<'de>,
    {
        match Option::<ByteBuf>::deserialize(deserializer)? {
            Some(buf) => Ok(Some(Arc::new(buf.into_vec()))),
            None => Ok(None),
        }
    }
}

#[allow(dead_code)]
#[cfg(feature = "seed_schema")]
pub(crate) fn id_schema(_: &mut schemars::r#gen::SchemaGenerator) -> schemars::schema::Schema {
    use schemars::schema::{InstanceType, Schema, SchemaObject, SingleOrVec};
    let schema = SchemaObject {
        instance_type: Some(SingleOrVec::Vec(vec![
            InstanceType::String,
            InstanceType::Integer,
        ])),
        ..Default::default()
    };
    Schema::Object(schema)
}
@{-"\n"}@