use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use std::time::Duration;
use br_crypto::hash::u8_to_md5;
use lettre::{Message, SmtpTransport, Transport};
use lettre::message::{Attachment, Mailbox, MultiPart, SinglePart};
use lettre::message::header::ContentType;
use lettre::transport::smtp::authentication::Credentials;
use crate::{Receive, Sender};

#[derive(Clone, Debug)]
pub struct Smtp {
    /// 邮件地址
    host: String,
    /// 邮件端口
    port: u16,
    /// 发件人
    name: String,
    /// 发件箱
    mail: String,
    /// 邮件密码
    pass: String,
    /// 收件人列表
    to_vec: Vec<Mailbox>,
    /// 抄送人列表
    cc_vec: Vec<Mailbox>,
    /// 发送消息文本
    body_text: String,
    /// 发送消息网页
    body_html: String,
    /// 主题
    subject: String,
    /// 附件
    files: HashMap<String, SinglePart>,
}

impl Smtp {
    pub fn new(host: String, port: u16, name: String, mail: String, pass: String) -> Self {
        Self {
            host,
            port,
            name,
            mail,
            pass,
            to_vec: Vec::new(),
            cc_vec: Vec::new(),
            body_text: "".to_string(),
            body_html: "".to_string(),
            subject: "".to_string(),
            files: HashMap::new(),
        }
    }
}

impl Sender for Smtp {
    /// 设置发件人信息
    fn set_from(&mut self, name: &str) -> &mut dyn Sender {
        self.name = name.to_string();
        self
    }

    /// 收件人
    /// * name 收件人名称
    /// * mail 收件箱
    fn set_to(&mut self,  name: &str, mail: &str) -> &mut dyn Sender {
        let mut new_name = String::new();
        for c in name.chars() {
            if !matches!(c, '@' | '(' | ')' | '<' | '>' | ':' | ';' | ',' | '.') {
                new_name.push(c);
            }
        }
        
        self.to_vec.push(format!("{new_name} <{mail}>").parse().unwrap());
        self
    }

    /// 抄送人
    /// * name 抄送人名称
    /// * mail 收件箱
    fn set_cc(&mut self, name: &str, mail: &str) -> &mut dyn Sender {
        let mut new_name = String::new();
        for c in name.chars() {
            if !matches!(c, '@' | '(' | ')' | '<' | '>' | ':' | ';' | ',' | '.') {
                new_name.push(c);
            }
        }
        self.cc_vec.push(format!("{new_name} <{mail}>").parse().unwrap());
        self
    }
    /// 邮件正文
    fn set_body(&mut self, text: &str, html: &str) -> &mut dyn Sender {
        if !text.is_empty() {
            self.body_text = text.to_string();
        }
        if !html.is_empty() {
            self.body_html = html.to_string();
        }
        self
    }
    /// 设置主题
    fn set_subject(&mut self, subject: &str) -> &mut dyn Sender {
        self.subject = subject.to_string();
        self
    }
    /// 附件
    fn set_file(&mut self, name: &str, data: Vec<u8>, content_type: &str) -> &mut dyn Sender {
        if self.files.get(&*name.to_string()).is_none() {
            let files = Attachment::new(name.to_string()).body(data.clone(), ContentType::parse(content_type).unwrap());
            self.files.insert(name.to_string(), files);
        }
        self
    }
    /// 发送
    ///
    /// * subject 主题
    /// * body 内容
    /// subject: &str, body_text: &str, body_html: Vec<u8>, files: Vec<SinglePart>
    fn send(&mut self) -> Result<(Vec<u8>, usize, String), Error> {
        if self.to_vec.is_empty() {
            return Err(Error::new(ErrorKind::Other, format!("请填写收件人")));
        }
        if self.body_text.is_empty() && self.body_html.is_empty() {
            return Err(Error::new(ErrorKind::Other, format!("请填写邮件内容")));
        }
        let sub = self.subject.clone();

        let mut builder = Message::builder().from(format!("{} <{}>", self.name, self.mail).parse().unwrap()).subject(sub);


        for item in self.to_vec.clone() {
            builder = builder.to(item.clone())
        }

        if !self.cc_vec.is_empty() {
            for item in self.cc_vec.clone() {
                builder = builder.cc(item.clone())
            }
        }

        // 发件这里传入参数html网页格式用Vec<u8>字节码
        let mut body = MultiPart::alternative().multipart(
            MultiPart::alternative_plain_html(String::from(self.body_text.clone()), String::from(self.body_html.clone()))
        );

        if self.files.len() > 0 {
            for (_, file) in self.files.iter() {
                body = body.singlepart(file.clone()).clone();
            }
        }

        let email = builder.multipart(body.clone()).unwrap();

        let mailer = match self.port {
            25 | 587 => {
                SmtpTransport::starttls_relay(self.host.as_str())
                    .unwrap()
                    .port(self.port)
                    .credentials(Credentials::new(self.mail.to_string(), self.pass.to_string()))
                    .timeout(Some(Duration::from_secs(3)))
                    .build()
            }
            _ => {
                SmtpTransport::relay(self.host.as_str())
                    .unwrap()
                    .port(self.port)
                    .credentials(Credentials::new(self.mail.to_string(), self.pass.to_string()))
                    .timeout(Some(Duration::from_secs(3)))
                    .build()
            }
        };
        match mailer.send(&email) {
            Ok(_) => {
                let data = email.formatted();
                Ok((data.clone(), data.len(), u8_to_md5(data).leak().to_string()))
            }
            Err(e) => Err(Error::new(ErrorKind::Other, format!("发送失败: {}", e.to_string())))
        }
    }
}

impl Receive for Smtp {
    fn get_total(&mut self) -> Result<usize, std::io::Error> {
        todo!()
    }

    fn get_id_list(&mut self) -> Result<Vec<String>, Error> {
        todo!()
    }

    fn get_id_info(&mut self, _id: &str) -> Result<(Vec<u8>, usize, String), Error> {
        todo!()
    }

    fn del_id(&mut self, _id: &str) -> Result<bool, Error> {
        todo!()
    }
}