use std::ops::Deref;

use crate::feed_api::FeedApiError;
use crate::models::{ApiSecret, Url};

pub struct InoreaderOAuth {
    pub base_uri: Url,
    pub client_id: String,
    pub client_secret: String,
    pub redirect_uri: String,
    csrf_protection: String,

    pub create_secret_url: Url,
}

impl InoreaderOAuth {
    pub fn new() -> Self {
        InoreaderOAuth {
            base_uri: Url::parse("https://www.inoreader.com/").unwrap(),
            client_id: "999997669".into(),
            client_secret: "y0NxO1RQOZ1TduNq3tu03m1zAwRhw_nO".into(),
            redirect_uri: "http://localhost".into(),
            csrf_protection: "123456".into(),

            create_secret_url: Url::parse(
                "https://www.inoreader.com/?show_dialog=preferences_dialog&amp;params={set_category:%27preferences_developer%27,ajax:true}",
            )
            .unwrap(),
        }
    }

    pub fn login_url(&self, custom_api_secret: Option<&ApiSecret>) -> String {
        let client_id = custom_api_secret
            .map(|secret| secret.client_id.deref())
            .unwrap_or_else(|| self.client_id.deref());
        format!(
            "https://www.inoreader.com/oauth2/auth?client_id={}&redirect_uri={}&response_type=code&scope=read+write&state={}",
            client_id, self.redirect_uri, self.csrf_protection
        )
    }

    pub fn redirect_uri(&self) -> String {
        self.redirect_uri.clone()
    }

    pub fn parse_redirected_url(&self, url: &Url) -> Result<String, FeedApiError> {
        if let Some(code) = url.query_pairs().find(|x| x.0 == "code")
            && let Some(state) = url.query_pairs().find(|x| x.0 == "state")
            && state.1 == self.csrf_protection
        {
            return Ok(code.1.to_string());
        }

        // FIXME: parse error message
        tracing::error!(%url, "Failed to parse redirected url");
        Err(FeedApiError::Login)
    }
}
