#![deny(unused_extern_crates)]
#![deny(warnings)]

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
pub use either::Either;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Value {
    Null,
    Bool(bool),
    Int(i64),
    F32(f32),
    F64(f64),
    String(String),
    DateTime(DateTime<Utc>),
    Blob(Vec<u8>),
}
impl From<i64> for Value {
    fn from(i: i64) -> Self {
        Self::Int(i)
    }
}
impl From<bool> for Value {
    fn from(b: bool) -> Self {
        Self::Bool(b)
    }
}
impl From<f32> for Value {
    fn from(f: f32) -> Self {
        Self::F32(f)
    }
}
impl From<f64> for Value {
    fn from(f: f64) -> Self {
        Self::F64(f)
    }
}
impl From<String> for Value {
    fn from(s: String) -> Self {
        Self::String(s)
    }
}

impl From<&str> for Value {
    fn from(s: &str) -> Self {
        Self::String(s.into())
    }
}

impl From<DateTime<Utc>> for Value {
    fn from(dt: DateTime<Utc>) -> Self {
        Self::DateTime(dt)
    }
}

pub trait FromValueRef {
    fn from_value_ref(value: &Value) -> Self;
}

impl FromValueRef for i64 {
    fn from_value_ref(v: &Value) -> Self {
        match v {
            Value::Null => 0,
            Value::Bool(b) => {
                if *b {
                    1
                } else {
                    0
                }
            }
            Value::Int(i) => *i,
            Value::F32(f) => *f as _,
            Value::F64(f) => *f as _,
            Value::String(s) => i64::from_str_radix(&s, 10).unwrap_or(0),
            Value::DateTime(dt) => dt.timestamp() as _,
            Value::Blob(_) => 0,
        }
    }
}
impl FromValueRef for i32 {
    fn from_value_ref(v: &Value) -> Self {
        match v {
            Value::Null => 0,
            Value::Bool(b) => {
                if *b {
                    1
                } else {
                    0
                }
            }
            Value::Int(i) => *i as _,
            Value::F32(f) => *f as _,
            Value::F64(f) => *f as _,
            Value::String(s) => i32::from_str_radix(&s, 10).unwrap_or(0),
            Value::DateTime(dt) => dt.timestamp() as _,
            Value::Blob(_) => 0,
        }
    }
}
impl FromValueRef for bool {
    fn from_value_ref(v: &Value) -> Self {
        match v {
            Value::Null => false,
            Value::Bool(b) => *b,
            Value::Int(i) => *i != 0,
            Value::F32(f) => *f != 0.,
            Value::F64(f) => *f != 0.,
            Value::String(s) => s == "true" || s == "True" || s == "1",
            Value::DateTime(dt) => dt.timestamp() != 0,
            Value::Blob(b) => b.len() != 0,
        }
    }
}

impl FromValueRef for f32 {
    fn from_value_ref(v: &Value) -> Self {
        match v {
            Value::Null => 0.,
            Value::Bool(b) => {
                if *b {
                    1.
                } else {
                    0.
                }
            }
            Value::Int(i) => *i as _,
            Value::F32(f) => *f,
            Value::F64(f) => *f as _,
            Value::String(s) => s.parse().unwrap_or(0.),
            Value::DateTime(dt) => dt.timestamp() as _,
            Value::Blob(_) => 0.,
        }
    }
}

impl FromValueRef for f64 {
    fn from_value_ref(v: &Value) -> Self {
        match v {
            Value::Null => 0.,
            Value::Bool(b) => {
                if *b {
                    1.
                } else {
                    0.
                }
            }
            Value::Int(i) => *i as _,
            Value::F32(f) => *f as _,
            Value::F64(f) => *f,
            Value::String(s) => s.parse().unwrap_or(0.),
            Value::DateTime(dt) => dt.timestamp() as _,
            Value::Blob(_) => 0.,
        }
    }
}

impl FromValueRef for String {
    fn from_value_ref(v: &Value) -> Self {
        match v {
            Value::Null => Default::default(),
            Value::Bool(b) => {
                if *b {
                    "true".into()
                } else {
                    "false".into()
                }
            }
            Value::Int(i) => i.to_string(),
            Value::F32(f) => f.to_string(),
            Value::F64(f) => f.to_string(),
            Value::String(s) => s.clone(),
            Value::DateTime(dt) => dt.to_rfc3339(),
            Value::Blob(_) => Default::default(),
        }
    }
}

impl FromValueRef for DateTime<Utc> {
    fn from_value_ref(v: &Value) -> Self {
        match v {
            Value::DateTime(dt) => dt.clone(),
            _ => Default::default(),
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Col {
  pub value: Value,
  pub ordinal: u64,
}

impl Col {
  pub fn new(value: Value, ordinal: u64) -> Self {
    Self {
      value,
      ordinal,
    }
  }
}

impl From<(Value,u64)> for Col {
  fn from((value,ordinal): (Value,u64))->Self {
    Self {
      value,
      ordinal,
    }
  }
}

impl std::ops::Deref for Col {
    type Target = Value;
    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl std::ops::DerefMut for Col {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.value
    }
}

#[derive(Serialize, Deserialize, Debug, Default)]
pub struct Row {
    pub columns: Vec<Column>,
    pub inner: Vec<Col>,
}

impl std::ops::Deref for Row {
    type Target = Vec<Col>;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl std::ops::DerefMut for Row {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl Row {
    pub fn get<T: FromValueRef>(&self, idx: usize) -> T {
        T::from_value_ref(&self[idx])
    }
}

impl From<(Vec<Column>,Vec<Col>)> for Row {
    fn from((columns,inner): (Vec<Column>,Vec<Col>)) -> Self {
        Self { columns, inner }
    }
}


pub type Rows = Vec<Row>;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum TypeInfo {
    Null,
    Int,
    Float,
    Text,
    Blob,
    Numeric,
    Bool,
    Int64,
    Date,
    Time,
    DateTime,
}
/*
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TypeInfo {
  pub is_null: bool,
  pub name: String,
}
*/
impl TypeInfo {
  pub fn is_null(&self) -> bool {
    match self {
      TypeInfo::Null=>true,
      _=>false,
    }
  }
  pub fn name(&self) -> &'static str {
    match self {
      Self::Null => "NULL",
      Self::Int => "INT",
      Self::Float => "FLOAT",
      Self::Text => "FLOAT",
      Self::Blob => "BLOB",
      Self::Numeric => "NUMERIC",
      Self::Bool => "BOOL",
      Self::Int64 => "INTEGER",
      Self::Date => "DATE",
      Self::Time => "TIME",
      Self::DateTime => "DATETIME",
    }
  }
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Column {
  pub ordinal: usize,
  pub name: String,
  pub type_info: TypeInfo,
}
/*
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Rows {
  pub description: ColumnsDescription,
  pub inner: Vec<Row>,
}

impl std::ops::Deref for Rows {
  type Target = Vec<Row>;
  fn deref(&self) -> &Self::Target {
    &self.inner
  }
}

impl std::ops::DerefMut for Rows {
  fn deref_mut(&mut self) -> &mut Self::Target {
    &mut self.inner
  }
}
*/
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct QueryResult {
  pub last_insert_rowid: i64,
  pub changes: u64,
}


#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum Message {
    Execute(String, Vec<Value>),
    Fetch(String, Vec<Value>),
    FetchOne(String, Vec<Value>),
    FetchOptional(String, Vec<Value>),
    FetchMany(String, Vec<Value>),
}

impl Message {
    pub fn sql(&self) -> &str {
        match self {
            Self::Execute(s, _) => s.as_str(),
            Self::Fetch(s, _) => s.as_str(),
            Self::FetchOne(s, _) => s.as_str(),
            Self::FetchOptional(s, _) => s.as_str(),
            Self::FetchMany(s, _) => s.as_str(),
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub enum MessageResponse {
    Rows(Rows),
    QueryResult(QueryResult),
    QueryResultsAndRows(Vec<Result<Either<QueryResult,Row>,String>>),
    Error(String),
}



#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct RSQliteClientTlsConfig {
    pub cert_paths: Vec<String>,
    pub accept_invalid_certificates: bool,
}

impl RSQliteClientTlsConfig {
    pub fn accept_invalid_certificates(mut self, accept_invalid_certificates: bool) -> Self {
        self.accept_invalid_certificates = accept_invalid_certificates;
        self
    }
    pub fn add_cert_path(mut self, cert_path: String) -> Self {
        self.cert_paths.push(cert_path);
        self
    }
}
/*
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct RSQliteNodeConfig {
    pub tls_config: Option<RSQliteNodeTlsConfig>,
}
*/

/*
pub use std::sync::atomic::{AtomicBool,Ordering};
pub const IN_TEST: AtomicBool = AtomicBool::new(false);
*/