use std::fs;
use json::JsonValue;
use lettre::{Message, SmtpTransport, Transport};
use lettre::message::{Attachment, header, MultiPart, SinglePart};
use lettre::message::header::ContentType;
use lettre::transport::smtp::authentication::Credentials;
use log::info;

#[derive(Clone)]
pub struct Smtp {
    default: String,
    connections: JsonValue,

    send_name: String,
    send_mail: String,
    send_pass: String,

    smtp_host: String,
    smtp_port: u16,

    to_name: String,
    to_mail: String,
    reply_to_name: String,
    reply_to_mail: String,
}

impl Smtp {
    /// 初始化
    ///
    /// * config 配置文件
    /// ````json
    /// {
    ///   "pop3_host": "pop.test.com",
    ///   "pop3_port": 995,
    ///   "smtp_host": "smtp.test.com",
    ///   "smtp_port": 465,
    ///   "send_email": "tests@email.com",
    ///   "send_pass": ""
    /// }
    /// ````
    pub fn connect(config: JsonValue) -> Self {
        if config.is_empty() {
            return Self {
                default: "".to_string(),
                connections: JsonValue::Null,
                send_name: "".to_string(),
                send_mail: "".to_string(),
                send_pass: "".to_string(),
                smtp_host: "".to_string(),
                smtp_port: 0,
                to_name: "".to_string(),
                to_mail: "".to_string(),
                reply_to_name: "".to_string(),
                reply_to_mail: "".to_string(),
            };
        }
        let default = config["default"].to_string();
        let connections = config["connections"].clone();
        let connection = connections[default.clone()].clone();

        let smtp_host = connection["smtp_host"].to_string();
        let smtp_port = connection["smtp_port"].as_u16().unwrap();

        let send_name = connection["send_name"].to_string();
        let send_mail = connection["send_mail"].to_string();
        let send_pass = connection["send_pass"].to_string();

        Self {
            default,
            connections,
            send_name,
            send_mail,
            send_pass,
            smtp_host,
            smtp_port,
            to_name: String::new(),
            to_mail: String::new(),
            reply_to_name: String::new(),
            reply_to_mail: String::new(),
        }
    }

    pub fn change_connection(&mut self, name: &str) {
        let connection = self.connections[name.clone()].clone();
        self.default = name.to_string();
        self.smtp_host = connection["smtp_host"].to_string();
        self.smtp_port = connection["smtp_port"].as_u16().unwrap();
        self.send_name = connection["send_name"].to_string();
        self.send_mail = connection["send_mail"].to_string();
        self.send_pass = connection["send_pass"].to_string();
    }

    /// 设置发件人名称
    pub fn set_send_name(&mut self, send_name: &str) -> &mut Self {
        self.send_name = send_name.to_string();
        self
    }

    /// 收件人
    /// * name 收件人名称
    /// * mail 收件箱
    pub fn to(&mut self, name: &str, mail: &str) -> &mut Self {
        self.to_name = name.to_string();
        self.to_mail = mail.to_string();
        self
    }
    /// 抄送人
    /// * name 收件人名称
    /// * mail 收件箱
    pub fn reply_to(&mut self, name: &str, mail: &str) -> &mut Self {
        self.reply_to_name = name.to_string();
        self.reply_to_mail = mail.to_string();
        self
    }

    /// 附件
    pub fn add_file(&mut self, path: &str, name: &str, content_type: &str) -> SinglePart {
        let content_type = {
            match content_type {
                "pdf" => {
                    ContentType::parse("application/pdf").unwrap()
                }
                "html" => {
                    ContentType::parse("text/html").unwrap()
                }
                "jpeg" => {
                    ContentType::parse("image/jpeg").unwrap()
                }
                "json" => {
                    ContentType::parse("application/json").unwrap()
                }
                _ => {
                    ContentType::parse("text/plain").unwrap()
                }
            }
        };
        return Attachment::new(name.to_string()).body(fs::read(path.clone()).unwrap(), content_type);
    }
    /// 发送
    ///
    /// * subject 主题
    /// * body 内容
    pub fn send(&mut self, subject: &str, body: &str, files: Vec<SinglePart>) -> bool {
        let mut builder = Message::builder().from(format!("{} <{}>",self.send_name,self.send_mail).parse().unwrap()).subject(subject);

        builder = builder.to(format!("{} <{}>", self.to_name, self.to_mail).parse().unwrap());

        if !self.reply_to_name.is_empty() {
            builder = builder.reply_to(format!("{} <{}>", self.reply_to_name, self.reply_to_mail).parse().unwrap());
        }

        let mut body = MultiPart::alternative().multipart(
            MultiPart::alternative_plain_html(String::from("text/plain"), String::from(body))
        ).singlepart(SinglePart::builder().header(header::ContentType::TEXT_PLAIN).body(String::from(body)));

        if !files.is_empty() {
            for file in files.iter() {
                body = body.singlepart(file.clone()).clone();
            }
        }

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

        let mailer = SmtpTransport::relay(self.smtp_host.as_str())
            .unwrap()
            .port(self.smtp_port)
            .credentials(Credentials::new(self.send_mail.to_string(), self.send_pass.to_string()))
            .build();
        match mailer.send(&email) {
            Ok(_) => {
                true
            }
            Err(e) => {
                info!("错误: {}", e);
                false
            }
        }
    }
}