use crate::dat::DatPayload;
use crate::dat_key::{DatKeySet, DatKeySetActive};
use crate::error::DatError;
use crate::util::now_unix_timestamp;
use itertools::Itertools;
use std::sync::RwLock;
use time::OffsetDateTime;

pub struct DatKeyStore {
    keys: RwLock<Vec<DatKeySet>>,
    issue_key: RwLock<Option<DatKeySetActive>>,
    verify_keys: RwLock<Vec<DatKeySetActive>>,
}

impl DatKeyStore {
    pub fn new() -> Self {
        DatKeyStore {
            keys: RwLock::new(vec![]),
            issue_key: RwLock::new(None),
            verify_keys: RwLock::new(vec![]),
        }
    }
    pub fn verify(&self, dat: String) -> Result<DatPayload, DatError> {
        let data = DatKeySetActive::split(&dat)?;
        let kid = data[0];
        if let Some(ks) = self.verify_keys.read().unwrap().iter().find(|e| e.kid == kid) {
            ks.verify_by_split_unsafe(data)
        } else {
            Err(DatError::DatError(format!("kid not found: {kid}")))
        }
    }

    pub fn clear_key(&self) {
        *self.keys.write().unwrap() = vec![];
    }

    pub fn add_key(&self, key: DatKeySet) -> Result<(), DatError> {
        self.add_keys(vec![key], false)
    }

    pub fn add_keys_from_json(&self, json_keys: String, clear: bool) -> Result<(), DatError> {
        let keys = serde_json::from_str::<Vec<DatKeySet>>(&json_keys)
            .map_err(|e| DatError::KeyError(format!("from_json error: {json_keys}/{e}")))?;
        self.add_keys(keys, clear)
    }

    pub fn add_keys(&self, keys: Vec<DatKeySet>, clear: bool) -> Result<(), DatError> {
        let mut p_list = if clear { vec![] } else { self.keys.read().unwrap().clone() };
        let now = now_unix_timestamp()?;

        keys.iter().for_each(|key| {
            if !p_list.contains(key) {
                p_list.push(key.clone());
            }
        });

        let p_list = p_list.iter()
            .filter(|key| key.issue_end > now)
            .cloned()
            .sorted_by(|a, b| a.issue_begin.cmp(&b.issue_begin))
            .collect::<Vec<DatKeySet>>();

        *self.keys.write().unwrap() = p_list;

        Ok(())
    }

    pub fn get_json_keys(&self) -> String {
        serde_json::to_string(&*self.keys.read().unwrap()).unwrap()
    }

    pub fn get_keys(&self) -> Vec<DatKeySet> {
        self.keys.read().unwrap().clone()
    }

    pub fn apply(&self) -> Result<(), DatError> {
        let now = OffsetDateTime::now_utc().unix_timestamp();
        let list = self.keys.read().unwrap().clone();
        let mut issue_key_set: Option<DatKeySetActive> = None;
        let mut verify_key_set_list: Vec<DatKeySetActive> = vec![];

        for item in list.iter() {
            if (item.issue_end + item.token_lifetime as i64) >= now {
                verify_key_set_list.push(item.clone().into_active()?);
                if issue_key_set.is_none() {
                    if item.issue_begin <= now {
                        issue_key_set = Some(item.clone().into_active()?);
                    }
                }
            }
        }
        *self.issue_key.write().unwrap() = issue_key_set;
        *self.verify_keys.write().unwrap() = verify_key_set_list;
        Ok(())
    }
}
