//! 加密字符串

use std::ops::Deref;

use crate::{rand::RandList, URLCode, ORIGIN_KEY};

/// 加密编码结果
#[derive(Clone, Debug, Default)]
pub struct EncodeResult {
    /// 加密密钥
    pub key: String,
    /// 加密结果
    pub val: String,
}

impl EncodeResult {
    pub fn set_kv(key: String, val: String) -> Self {
        Self { key, val }
    }
}

pub trait EncodeFrom<T> {
    fn encode_from(&self, _: T) -> EncodeResult;
}
#[derive(Clone, Debug)]
pub struct Encode<'a> {
    key: &'a str,
    _result: EncodeResult,
}

impl Deref for Encode<'_> {
    type Target = EncodeResult;

    fn deref(&self) -> &Self::Target {
        &self._result
    }
}

impl Default for Encode<'_> {
    fn default() -> Self {
        Self {
            key: ORIGIN_KEY,
            _result: EncodeResult::default(),
        }
    }
}

impl<'a> Encode<'a> {
    pub fn new_key(key: &'a str) -> Self {
        Self {
            key,
            ..Self::default()
        }
    }

    pub fn new() -> Self {
        Self::default()
    }
}

impl EncodeFrom<&str> for Encode<'_> {
    fn encode_from(&self, s: &str) -> EncodeResult {
        let mut cipher = String::new();
        let origin_key = RandList::from(self.key).shuffle();

        URLCode::from(s)
            .vec_ref()
            .into_iter()
            .enumerate()
            .for_each(|(i, ref s)| {
                cipher.push_str(
                    origin_key
                        .get(
                            (i + origin_key
                                .get_index(s)
                                .expect("Can not find index at Encode"))
                                % origin_key.len(),
                        )
                        .unwrap(),
                );
            });

        EncodeResult {
            key: origin_key.join(""),
            val: cipher,
        }
    }
}

impl EncodeFrom<&String> for Encode<'_> {
    fn encode_from(&self, s: &String) -> EncodeResult {
        let mut cipher = String::new();
        let origin_key = RandList::from(self.key).shuffle();

        URLCode::from(s.clone())
            .vec_ref()
            .into_iter()
            .enumerate()
            .for_each(|(i, ref s)| {
                cipher.push_str(
                    origin_key
                        .get(
                            (i + origin_key.get_index(s).expect("Can not find index"))
                                % origin_key.len(),
                        )
                        .unwrap(),
                );
            });

        EncodeResult {
            key: origin_key.join(""),
            val: cipher,
        }
    }
}

impl EncodeFrom<String> for Encode<'_> {
    fn encode_from(&self, s: String) -> EncodeResult {
        let mut cipher = String::new();
        let origin_key = RandList::from(self.key).shuffle();

        URLCode::from(s)
            .vec_ref()
            .into_iter()
            .enumerate()
            .for_each(|(i, ref s)| {
                cipher.push_str(
                    origin_key
                        .get(
                            (i + origin_key.get_index(s).expect("Can not find index"))
                                % origin_key.len(),
                        )
                        .unwrap(),
                );
            });

        EncodeResult {
            key: origin_key.join(""),
            val: cipher,
        }
    }
}

impl EncodeFrom<URLCode> for Encode<'_> {
    fn encode_from(&self, s: URLCode) -> EncodeResult {
        let mut cipher = String::new();
        let origin_key = RandList::from(self.key).shuffle();

        s.vec_ref().into_iter().enumerate().for_each(|(i, ref s)| {
            cipher.push_str(
                origin_key
                    .get(
                        (i + origin_key.get_index(s).expect("Can not find index"))
                            % origin_key.len(),
                    )
                    .unwrap(),
            );
        });

        EncodeResult {
            key: origin_key.join(""),
            val: cipher,
        }
    }
}
