merge-ready 0.2.1

Show pull request merge blockers as concise prompt tokens
use std::process::ExitCode;

use clap::CommandFactory;

use crate::cli::{Cli, Command};
use crate::contexts::config::application::config_service::ConfigService;
use crate::contexts::config::infrastructure::toml_loader::TomlConfigRepository;
use crate::contexts::daemon::application::cache as daemon_cache_app;
use crate::contexts::daemon::infrastructure::daemon_client::{self as daemon_client, DaemonClient};
use crate::contexts::prompt::application::{
    OutputToken, errors::ErrorToken, prompt::ExecutionMode,
};
use crate::contexts::prompt::infrastructure::{gh::GhClient, logger::Logger};
use crate::contexts::prompt::interface::{
    cli::prompt::{self},
    presentation::{PresentationConfigPort, Presenter},
};

impl crate::contexts::prompt::application::errors::ErrorLogger for Logger {
    fn log(&self, msg: &str) {
        crate::contexts::prompt::infrastructure::logger::append_error(msg);
    }
}

pub(crate) struct ConfigAdapter(ConfigService);

impl ConfigAdapter {
    pub(crate) fn load() -> Self {
        Self(ConfigService::new(&TomlConfigRepository))
    }
}

impl PresentationConfigPort for ConfigAdapter {
    fn render_token(&self, token: &OutputToken) -> String {
        match token {
            OutputToken::MergeReady => self.0.render_merge_ready(),
            OutputToken::Conflict => self.0.render_conflict(),
            OutputToken::UpdateBranch => self.0.render_update_branch(),
            OutputToken::SyncUnknown => self.0.render_sync_unknown(),
            OutputToken::CiFail => self.0.render_ci_fail(),
            OutputToken::CiAction => self.0.render_ci_action(),
            OutputToken::ReviewRequested => self.0.render_review(),
        }
    }

    fn render_error_token(&self, token: ErrorToken) -> String {
        match token {
            ErrorToken::AuthRequired => self.0.render_auth_required(),
            ErrorToken::RateLimited => self.0.render_rate_limited(),
            ErrorToken::ApiError => self.0.render_api_error(),
        }
    }
}

pub fn run(cli: Cli) -> ExitCode {
    match cli.command {
        Some(Command::Prompt(args)) => match prompt::resolve_mode(&args) {
            ExecutionMode::Direct => {
                crate::contexts::prompt::interface::cli::prompt::direct::run(
                    &GhClient::new(),
                    &Logger,
                    ConfigAdapter::load(),
                );
                ExitCode::SUCCESS
            }
            ExecutionMode::Cached => {
                prompt::cached::run(
                    crate::contexts::prompt::infrastructure::repo_id::get,
                    daemon_client::query_via_daemon,
                );
                ExitCode::SUCCESS
            }
        },
        Some(Command::Config(args)) => {
            let config_path = crate::contexts::config::infrastructure::toml_loader::config_path();
            crate::contexts::config::interface::cli::run(
                &args,
                &TomlConfigRepository,
                config_path.as_deref(),
            )
        }
        Some(Command::Daemon(args)) => {
            let lifecycle =
                crate::contexts::daemon::infrastructure::daemon_lifecycle::DaemonLifecycle::new(
                    |repo_id: &str, cwd: &std::path::Path| {
                        let repo_id = repo_id.to_owned();
                        let tokens = crate::contexts::prompt::application::prompt::fetch_output(
                            &GhClient::new_in(cwd.to_path_buf()),
                            &Logger,
                        );
                        if let Some(tokens) = tokens {
                            let output =
                                Presenter::new(ConfigAdapter::load()).render_to_string(&tokens);
                            daemon_cache_app::update(&DaemonClient, &repo_id, &output);
                        }
                    },
                );
            crate::contexts::daemon::interface::cli::daemon::run(args.subcommand, &lifecycle);
            ExitCode::SUCCESS
        }
        None => {
            let _ = Cli::command().print_help();
            ExitCode::SUCCESS
        }
    }
}