use crate::models::ArticleID;
use crate::models::Url;
use crate::schema::enclosures;
use diesel::backend::Backend;
use diesel::deserialize;
use diesel::deserialize::FromSql;
use diesel::serialize;
use diesel::serialize::{Output, ToSql};
use diesel::sql_types::Integer;
use diesel::sqlite::Sqlite;
use std::io::Write;

#[derive(Identifiable, Queryable, PartialEq, Debug, Insertable)]
#[primary_key(article_id)]
#[table_name = "enclosures"]
pub struct Enclosure {
    pub article_id: ArticleID,
    pub url: Url,
    pub enclosure_type: EnclosureType,
}

//------------------------------------------------------------------

#[derive(PartialEq, Debug, Clone, AsExpression, FromSqlRow)]
#[sql_type = "Integer"]
pub enum EnclosureType {
    Image,
    Video,
    Audio,
    File,
}

impl EnclosureType {
    pub fn from_string(string: &str) -> EnclosureType {
        if string.contains("audio") {
            return EnclosureType::Audio;
        }
        if string.contains("video") {
            return EnclosureType::Video;
        }
        if string.contains("image") {
            return EnclosureType::Image;
        }

        EnclosureType::File
    }
}

impl FromSql<Integer, Sqlite> for EnclosureType {
    fn from_sql(bytes: Option<&<Sqlite as Backend>::RawValue>) -> deserialize::Result<Self> {
        let v = not_none!(bytes).read_integer();
        Ok(match v {
            1 => EnclosureType::Image,
            2 => EnclosureType::Video,
            3 => EnclosureType::Audio,
            4 => EnclosureType::File,
            _ => return Err("Should never happen".into()),
        })
    }
}

impl ToSql<Integer, Sqlite> for EnclosureType {
    fn to_sql<W: Write>(&self, out: &mut Output<'_, W, Sqlite>) -> serialize::Result {
        let v = match *self {
            EnclosureType::Image => 1,
            EnclosureType::Video => 2,
            EnclosureType::Audio => 3,
            EnclosureType::File => 4,
        };
        ToSql::<Integer, Sqlite>::to_sql(&v, out)
    }
}
