use rmux_client::Connection;
use rmux_proto::CapturePaneRequest;

use crate::cli_args::{CapturePaneArgs, TargetSpec};

use super::{resolve_pane_target_or_current, ExitFailure};

pub(super) struct PendingCapturePaneRequest {
    target: Option<TargetSpec>,
    start: Option<i64>,
    end: Option<i64>,
    print: bool,
    buffer_name: Option<String>,
    alternate: bool,
    escape_ansi: bool,
    escape_sequences: bool,
    join_wrapped: bool,
    use_mode_screen: bool,
    preserve_trailing_spaces: bool,
    do_not_trim_spaces: bool,
    pending_input: bool,
    quiet: bool,
    start_is_absolute: bool,
    end_is_absolute: bool,
}

pub(super) fn capture_pane_request(
    args: CapturePaneArgs,
) -> Result<PendingCapturePaneRequest, ExitFailure> {
    let (start, start_is_absolute) = parse_capture_bound(args.start.as_deref(), "-S")?;
    let (end, end_is_absolute) = parse_capture_bound(args.end.as_deref(), "-E")?;

    Ok(PendingCapturePaneRequest {
        target: args.target,
        start,
        end,
        print: args.print,
        buffer_name: args.buffer_name,
        alternate: args.alternate,
        escape_ansi: args.escape_ansi,
        escape_sequences: args.escape_sequences,
        join_wrapped: args.join_wrapped,
        use_mode_screen: args.use_mode_screen,
        preserve_trailing_spaces: args.preserve_trailing_spaces,
        do_not_trim_spaces: args.do_not_trim_spaces,
        pending_input: args.pending_input,
        quiet: args.quiet,
        start_is_absolute,
        end_is_absolute,
    })
}

pub(super) fn build_capture_pane_request(
    connection: &mut Connection,
    request: PendingCapturePaneRequest,
) -> Result<CapturePaneRequest, ExitFailure> {
    Ok(CapturePaneRequest {
        target: resolve_pane_target_or_current(
            connection,
            request.target.as_ref(),
            "capture-pane",
        )?,
        start: request.start,
        end: request.end,
        print: request.print,
        buffer_name: request.buffer_name,
        alternate: request.alternate,
        escape_ansi: request.escape_ansi,
        escape_sequences: request.escape_sequences,
        join_wrapped: request.join_wrapped,
        use_mode_screen: request.use_mode_screen,
        preserve_trailing_spaces: request.preserve_trailing_spaces,
        do_not_trim_spaces: request.do_not_trim_spaces,
        pending_input: request.pending_input,
        quiet: request.quiet,
        start_is_absolute: request.start_is_absolute,
        end_is_absolute: request.end_is_absolute,
    })
}

fn parse_capture_bound(
    value: Option<&str>,
    flag: &str,
) -> Result<(Option<i64>, bool), ExitFailure> {
    match value {
        None => Ok((None, false)),
        Some("-") => Ok((None, true)),
        Some(value) => value
            .parse::<i64>()
            .map(|value| (Some(value), false))
            .map_err(|error| {
                ExitFailure::new(1, format!("invalid {} value '{}': {}", flag, value, error))
            }),
    }
}
