use std::collections::HashMap;

use common::config::{self, Password};

use crate::App;
use crate::prelude::*;
use crate::widget::EncryptionPasswordDialog;

pub async fn password_dialog(
    repo: &config::Repository,
    purpose: &str,
    keyring_error: Option<&str>,
) -> Option<config::Password> {
    // TODO: accept transient_for argument
    let window = App::default().main_window();

    EncryptionPasswordDialog::new()
        .present_with(&window, repo, purpose, keyring_error)
        .await
}

pub async fn store_password(config: &config::Backup, password: &Password) -> Result<()> {
    tracing::debug!("Storing new password at secret service");
    set_password(config, password)
        .await
        .map_err(|err| Message::from_secret_service(gettext("Failed to Store Password"), err))?;

    Ok(())
}

pub async fn remove_password(config: &config::Backup, remove_all: bool) -> Result<()> {
    // check if other configs using this repo exist
    if !remove_all
        && BACKUP_CONFIG
            .load()
            .iter()
            .any(|x| x.id != config.id && x.repo_id == config.repo_id)
    {
        tracing::debug!("Not removing password because other configs need it");
    } else {
        tracing::debug!("Removing password from secret service");
        delete_passwords(config).await.map_err(|err| {
            Message::from_secret_service(
                gettext("Failed to remove potentially remaining passwords from key storage."),
                err,
            )
        })?;
    }

    Ok(())
}

async fn set_password(
    config: &config::Backup,
    password: &Password,
) -> std::result::Result<(), oo7::Error> {
    tracing::debug!("Starting to store password");
    let keyring = common::utils::oo7_workaround::load_keyring().await?;

    keyring
        .create_item(
            // Translators: This is the description for entries in the password database.
            &gettextf("Pika Backup “{}”", [&config.repo.location()]),
            &HashMap::from([("repo-id", config.repo_id.as_str())]),
            password.as_bytes(),
            true,
        )
        .await?;

    tracing::debug!("Storing password returned");

    Ok(())
}

async fn delete_passwords(config: &config::Backup) -> std::result::Result<(), oo7::Error> {
    tracing::debug!("Starting to clear passwords");

    let keyring = common::utils::oo7_workaround::load_keyring().await?;
    keyring
        .delete(&HashMap::from([("repo-id", config.repo_id.as_str())]))
        .await?;

    tracing::debug!("Clearing password returned");
    Ok(())
}
