use crate::models::{FeedID, Url};
use crate::schema::feeds;
use feed_rs::model::Feed as FeedRS;
use std::hash::{Hash, Hasher};

#[derive(Identifiable, Clone, Insertable, Queryable, Eq, Debug)]
#[diesel(primary_key(feed_id))]
#[diesel(table_name = feeds)]
#[diesel(check_for_backend(SQLite))]
pub struct Feed {
    pub feed_id: FeedID,
    pub label: String,
    pub website: Option<Url>,
    pub feed_url: Option<Url>,
    pub icon_url: Option<Url>,
    pub error_count: i32,
    pub error_message: Option<String>,
}

impl Hash for Feed {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.feed_id.hash(state);
    }
}

impl PartialEq for Feed {
    fn eq(&self, other: &Feed) -> bool {
        self.feed_id == other.feed_id
    }
}

impl Feed {
    pub fn from_feed_rs(feed: &FeedRS, title: Option<String>, url: &Url) -> Self {
        let title = match title {
            Some(title) => title,
            None => match &feed.title {
                Some(title) => title.content.clone(),
                None => "Unknown Feed".into(),
            },
        };

        // see if there is a link with rel='alternate' -> this is probably what we want
        let website = feed
            .links
            .iter()
            .find(|link| link.rel == Some("alternate".to_owned()))
            .and_then(|link| Url::parse(&link.href).ok());

        // if no link with rel='alternate' could be found, try for a link without rel
        let website = match website {
            Some(website) => Some(website),
            None => feed
                .links
                .iter()
                .find(|link| link.rel.is_none())
                .and_then(|link| Url::parse(&link.href).ok()),
        };

        // otherwise just take the first link
        let website = match website {
            Some(website) => Some(website),
            None => feed.links.first().and_then(|link| Url::parse(&link.href).ok()),
        };

        let icon_url = match feed.icon.as_ref().and_then(|icon| Url::parse(&icon.uri).ok()) {
            Some(url) => Some(url),
            None => feed.logo.as_ref().and_then(|logo| Url::parse(&logo.uri).ok()),
        };

        Feed {
            feed_id: FeedID::new(url.as_str()),
            label: title,
            website,
            feed_url: Some(url.clone()),
            icon_url,
            error_count: 0,
            error_message: None,
        }
    }
}

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

#[derive(Queryable, Debug)]
#[diesel(check_for_backend(SQLite))]
pub struct FeedCount {
    pub feed_id: FeedID,
    pub count: i64,
}
