use std::convert::Infallible;
use anyhow::{Context, Result};
use console::Term;
use hyper::{Body, Request, Response};
use tokio::sync::mpsc::Sender;
use super::WEB_PAYMENTS_URL;
use crate::commands::payment::utils::{format_payment_methods, get_all_payment_methods};
use crate::state::http::HttpClient;
use crate::utils::browser::listen_for_callback;
use crate::utils::urlify;
pub async fn get_payment_method_from_user(http: &HttpClient) -> Result<String> {
loop {
let payment_methods = get_all_payment_methods(http).await?;
let mut payment_methods_fmt = format_payment_methods(&payment_methods, false)?;
payment_methods_fmt.push("New payment method".to_string());
let payment_method_idx = dialoguer::Select::new()
.with_prompt("Select a payment method")
.items(&payment_methods_fmt)
.default(0)
.interact()?;
if payment_method_idx == payment_methods_fmt.len() - 1 {
let _ = Term::stderr().clear_last_lines(1);
let port = portpicker::pick_unused_port().with_context(|| {
"Could not find an unused port. Please make sure you have at least one port available."
})?;
let url = format!(
"{WEB_PAYMENTS_URL}?{}",
["callback", &format!("http://localhost:{port}/payment")].join("=")
);
if let Err(why) = webbrowser::open(&url) {
log::error!("Could not open web a browser: {why}",);
log::info!(
"Please open this URL in your browser: {}",
urlify(WEB_PAYMENTS_URL)
);
log::info!("Press enter to continue...");
let _ = std::io::stdin().read_line(&mut String::new());
Term::stderr().clear_last_lines(4)?;
} else {
log::info!("A browser window should have opened. If not, please open this URL in your browser: {}", urlify(&url));
log::info!("Waiting for payment method to be created...");
listen_for_callback(port, 10, |req, sender| {
Box::pin(request_handler(req, sender))
})
.await?;
}
let _ = Term::stdout().clear_last_lines(3);
} else {
return Ok(payment_methods[payment_method_idx].id.clone());
}
}
}
async fn request_handler(
req: Request<Body>,
sender: Sender<String>,
) -> Result<Response<Body>, Infallible> {
let path = req.uri().path();
if path == "/payment" {
sender.send("Payment method created".to_string()).await.ok();
return Ok(Response::builder()
.status(200)
.body("Payment method created".into())
.unwrap());
}
Ok(Response::builder()
.status(400)
.body("Bad request".into())
.unwrap())
}