use crate::domain::aggregates::identity_link::value_objects::ExternalSystem;
use crate::domain::aggregates::resource_usage::value_objects::{TimePeriod, UsageId};
use crate::domain::ports::notifier::Notifier;
use crate::domain::ports::repositories::ResourceUsageRepository;
use crate::interface::slack::app::SlackApp;
use crate::interface::slack::constants::*;
use crate::interface::slack::utility::{datetime_parser::parse_datetime, extract_form_data};
use slack_morphism::prelude::*;
pub async fn handle<R, N>(
app: &SlackApp<R, N>,
view_submission: &SlackInteractionViewSubmissionEvent,
) -> Result<Option<SlackViewSubmissionResponse>, Box<dyn std::error::Error + Send + Sync>>
where
R: ResourceUsageRepository + Send + Sync + 'static,
N: Notifier + Send + Sync + 'static,
{
let user_id = view_submission.user.id.clone();
let usage_id_str = extract_form_data::get_private_metadata(view_submission)
.ok_or("usage_idがprivate_metadataに設定されていません")?;
let usage_id = UsageId::from_string(usage_id_str.clone());
let start_date =
extract_form_data::get_selected_date(view_submission, ACTION_RESERVE_START_DATE)
.ok_or("開始日が選択されていません")?;
let start_time =
extract_form_data::get_selected_time(view_submission, ACTION_RESERVE_START_TIME)
.ok_or("開始時刻が選択されていません")?;
let end_date = extract_form_data::get_selected_date(view_submission, ACTION_RESERVE_END_DATE)
.ok_or("終了日が選択されていません")?;
let end_time = extract_form_data::get_selected_time(view_submission, ACTION_RESERVE_END_TIME)
.ok_or("終了時刻が選択されていません")?;
let start_datetime = parse_datetime(&start_date, &start_time)?;
let end_datetime = parse_datetime(&end_date, &end_time)?;
let time_period = TimePeriod::new(start_datetime, end_datetime)?;
let notes = extract_form_data::get_plain_text_input(view_submission, ACTION_RESERVE_NOTES);
let identity_link = app
.identity_repo()
.find_by_external_user_id(&ExternalSystem::Slack, user_id.as_ref())
.await?
.ok_or("ユーザーが登録されていません。まず /register-calendar を実行してください")?;
let owner_email = identity_link.email().clone();
let update_result = app
.update_resource_usage_usecase()
.execute(&usage_id, &owner_email, Some(time_period), notes)
.await;
let channel_id = app
.user_channel_map()
.read()
.unwrap()
.get(&user_id)
.cloned()
.ok_or("セッションの有効期限が切れました。もう一度コマンドを実行してください。")?;
let message_text = match update_result {
Ok(_) => "✅ 予約を更新しました".to_string(),
Err(e) => {
let error_msg = e.to_string();
if error_msg.contains("見つかりません") || error_msg.contains("NotFound") {
"❌ 申し訳ございません。この予約は既に削除されているか、見つかりませんでした。"
.to_string()
} else if error_msg.contains("権限") || error_msg.contains("Unauthorized") {
"❌ この予約を更新する権限がありません。".to_string()
} else if error_msg.contains("重複") || error_msg.contains("Conflict") {
"❌ 指定された時間帯は既に予約されています。".to_string()
} else {
format!("❌ 予約の更新に失敗しました: {}", error_msg)
}
}
};
let ephemeral_req = SlackApiChatPostEphemeralRequest::new(
channel_id,
user_id.clone(),
SlackMessageContent::new().with_text(message_text),
);
let session = app.slack_client().open_session(app.bot_token());
session.chat_post_ephemeral(&ephemeral_req).await?;
Ok(None)
}