use std::{error::Error, fs};

use lettre::{
    message::{header::ContentType, Attachment, MultiPart, SinglePart},
    transport::smtp::authentication::Credentials,
    Message, SmtpTransport, Transport,
};
use sqlx::SqlitePool;

use crate::tera::admin::mail::MailToSend;

use super::{family::Family, log::Log, role::Role, user::User};

pub struct Mail {}

impl Mail {
    pub async fn send(db: &SqlitePool, data: MailToSend<'_>, smtp_pw: String) -> bool {
        let mut email = Message::builder()
            .from(
                "ASKÖ Ruderverein Donau Linz <no-reply@rudernlinz.at>"
                    .parse()
                    .unwrap(),
            )
            .reply_to(
                "ASKÖ Ruderverein Donau Linz <info@rudernlinz.at>"
                    .parse()
                    .unwrap(),
            )
            .to("ASKÖ Ruderverein Donau Linz <no-reply@rudernlinz.at>"
                .parse()
                .unwrap());
        let role = Role::find_by_id(db, data.role_id).await.unwrap();
        for rec in role.mails_from_role(db).await {
            let splitted = rec.split(',');
            for single_rec in splitted {
                match single_rec.parse() {
                    Ok(new_bcc_mail) => email = email.bcc(new_bcc_mail),
                    Err(_) => {
                        Log::create(
                            db,
                            format!("Mail not sent to {rec}, because it could not be parsed"),
                        )
                        .await;
                    }
                }
            }
        }

        let mut multipart = MultiPart::mixed().singlepart(SinglePart::plain(data.body));

        for temp_file in &data.files {
            let content = fs::read(temp_file.path().unwrap()).unwrap();
            let media_type = format!("{}", temp_file.content_type().unwrap().media_type());
            let content_type = ContentType::parse(&media_type).unwrap();
            if let Some(name) = temp_file.name() {
                let attachment = Attachment::new(format!(
                    "{}.{}",
                    name,
                    temp_file.content_type().unwrap().extension().unwrap()
                ))
                .body(content, content_type);

                multipart = multipart.singlepart(attachment);
            }
        }

        let email = email.subject(data.subject).multipart(multipart).unwrap();

        let creds = Credentials::new("no-reply@rudernlinz.at".to_owned(), smtp_pw);

        let mailer = SmtpTransport::relay("mail.your-server.de")
            .unwrap()
            .credentials(creds)
            .build();

        // Send the email
        match mailer.send(&email) {
            Ok(_) => return true,
            Err(e) => println!("{:?}", e.source()),
        };
        false
    }

    pub async fn fees(db: &SqlitePool, smtp_pw: String) {
        let users = User::all_payer_groups(db).await;
        for user in users {
            if !user.has_role(db, "paid").await {
                let mut is_family = false;
                let mut send_to = String::new();
                match Family::find_by_opt_id(db, user.family_id).await {
                    Some(family) => {
                        is_family = true;
                        for member in family.members(db).await {
                            if let Some(mail) = member.mail {
                                send_to.push_str(&format!("{mail},"))
                            }
                        }
                    }
                    None => {
                        if let Some(mail) = &user.mail {
                            send_to.push_str(mail)
                        }
                    }
                }

                let fees = user.fee(db).await;
                if let Some(fees) = fees {
                    let mut content = format!(
                        "Liebes Vereinsmitglied, \n\n\
dein Vereinsbeitrag für das aktuelle Jahr beträgt {}€",
                        fees.sum_in_cents / 100,
                    );

                    if fees.parts.len() == 1 {
                        content.push_str(&format!(" ({}).\n", fees.parts[0].0))
                    } else {
                        content.push_str(". Dieser setzt sich aus folgenden Teilen zusammen: \n");
                        for (desc, fee_in_cents) in fees.parts {
                            content.push_str(&format!("- {}: {}€\n", desc, fee_in_cents / 100))
                        }
                    }
                    if is_family {
                        content.push_str(&format!(
                            "Dieser gilt für die gesamte Familie ({}).\n",
                            fees.name
                        ))
                    }
                    content.push_str("\nBitte überweise diesen auf folgendes Konto: IBAN: AT13 1200 0804 1300 1200. Auf https://app.rudernlinz.at/planned findest du einen QR Code, den du mit deiner Bankapp scannen kannst um alle Eingaben bereits ausgefüllt zu haben.\n\n\
Falls die Berechnung nicht stimmt (korrekte Preise findest du unter https://rudernlinz.at/unser-verein/gebuhren/) melde dich bitte bei it@rudernlinz.at. @Studenten: Bitte die aktuelle Studienbestätigung an it@rudernlinz.at schicken.\n\n\
Wenn du die Vereinsgebühren schon bezahlt hast, kannst du diese Mail einfach ignorieren.\n\n
Beste Grüße\n\
Der Vorstand
                                                                          ");
                    let mut email = Message::builder()
                        .from(
                            "ASKÖ Ruderverein Donau Linz <no-reply@rudernlinz.at>"
                                .parse()
                                .unwrap(),
                        )
                        .reply_to(
                            "ASKÖ Ruderverein Donau Linz <it@rudernlinz.at>"
                                .parse()
                                .unwrap(),
                        )
                        .to("ASKÖ Ruderverein Donau Linz <no-reply@rudernlinz.at>"
                            .parse()
                            .unwrap());
                    let splitted = send_to.split(',');
                    let mut send_mail = false;
                    for single_rec in splitted {
                        let single_rec = single_rec.trim();
                        match single_rec.parse() {
                            Ok(val) => {
                                email = email.bcc(val);
                                send_mail = true;
                            }
                            Err(_) => {
                                println!("Error in mail: {single_rec}");
                            }
                        }
                    }

                    if send_mail {
                        let email = email
                            .subject("ASKÖ Ruderverein Donau Linz | Vereinsgebühren")
                            .header(ContentType::TEXT_PLAIN)
                            .body(content)
                            .unwrap();

                        let creds =
                            Credentials::new("no-reply@rudernlinz.at".to_owned(), smtp_pw.clone());

                        let mailer = SmtpTransport::relay("mail.your-server.de")
                            .unwrap()
                            .credentials(creds)
                            .build();

                        // Send the email
                        mailer.send(&email).unwrap();
                    }
                }
            }
        }
    }

    pub async fn fees_final(db: &SqlitePool, smtp_pw: String) {
        let users = User::all_payer_groups(db).await;
        for user in users {
            if let Some(fee) = user.fee(db).await {
                if !fee.paid {
                    let mut is_family = false;
                    let mut send_to = String::new();
                    match Family::find_by_opt_id(db, user.family_id).await {
                        Some(family) => {
                            is_family = true;
                            for member in family.members(db).await {
                                if let Some(mail) = member.mail {
                                    send_to.push_str(&format!("{mail},"))
                                }
                            }
                        }
                        None => {
                            if let Some(mail) = &user.mail {
                                send_to.push_str(mail)
                            }
                        }
                    }

                    let fees = user.fee(db).await;
                    if let Some(fees) = fees {
                        let mut content = format!(
                            "Liebes Vereinsmitglied, \n\n\
wir möchten darauf hinweisen, dass wir deinen Mitgliedsbeitrag für das laufende Jahr bislang nicht verbuchen konnten. Es besteht die Möglichkeit, dass es sich hierbei um ein Versehen unsererseits handelt. Solltest du den Betrag bereits überwiesen haben, bitte kurz auf diese E-Mail antworten, damit wir es richtigstellen können.

Falls die Zahlung noch nicht erfolgt ist, bitten wir um umgehende Überweisung des ausstehenden Betrags, spätestens jedoch bis zum 31. März, auf unser Bankkonto.\n\n\
Dein Vereinsbeitrag für das aktuelle Jahr beträgt {}€",
                            fees.sum_in_cents / 100,
                        );

                        if fees.parts.len() == 1 {
                            content.push_str(&format!(" ({}).\n", fees.parts[0].0))
                        } else {
                            content
                                .push_str(". Dieser setzt sich aus folgenden Teilen zusammen: \n");
                            for (desc, fee_in_cents) in fees.parts {
                                content.push_str(&format!("- {}: {}€\n", desc, fee_in_cents / 100))
                            }
                        }
                        if is_family {
                            content.push_str(&format!(
                                "Dieser gilt für die gesamte Familie ({}).\n",
                                fees.name
                            ))
                        }
                        content.push_str("\n\
Gemäß § 7 Abs. 3 lit. c unseres Status behalten wir uns vor, bei ausbleibender Zahlung die Mitgliedschaft zu beenden. Dies möchten wir vermeiden und hoffen auf deine Unterstützung.\n\n\
Bei Fragen oder Problemen stehen wir gerne zur Verfügung.

Bankverbindung: IBAN: AT13 1200 0804 1300 1200 (Unter https://app.rudernlinz.at/planned findest du einen QR Code, den du mit deiner Bankapp scannen kannst um alle Eingaben bereits ausgefüllt zu haben.)

Mit freundlichen Grüßen,\n\
Der Vorstand");
                        let mut email = Message::builder()
                            .from(
                                "ASKÖ Ruderverein Donau Linz <no-reply@rudernlinz.at>"
                                    .parse()
                                    .unwrap(),
                            )
                            .reply_to(
                                "ASKÖ Ruderverein Donau Linz <it@rudernlinz.at>"
                                    .parse()
                                    .unwrap(),
                            )
                            .to("ASKÖ Ruderverein Donau Linz <no-reply@rudernlinz.at>"
                                .parse()
                                .unwrap());
                        let splitted = send_to.split(',');
                        let mut send_mail = false;
                        for single_rec in splitted {
                            let single_rec = single_rec.trim();
                            match single_rec.parse() {
                                Ok(val) => {
                                    email = email.bcc(val);
                                    send_mail = true;
                                }
                                Err(_) => {
                                    println!("Error in mail: {single_rec}");
                                }
                            }
                        }

                        if send_mail {
                            let email = email
                                .subject("Mahnung Vereinsgebühren | ASKÖ Ruderverein Donau Linz")
                                .header(ContentType::TEXT_PLAIN)
                                .body(content)
                                .unwrap();

                            let creds = Credentials::new(
                                "no-reply@rudernlinz.at".to_owned(),
                                smtp_pw.clone(),
                            );

                            let mailer = SmtpTransport::relay("mail.your-server.de")
                                .unwrap()
                                .credentials(creds)
                                .build();

                            // Send the email
                            mailer.send(&email).unwrap();
                        }
                    }
                }
            }
        }
    }
}
