use tempfile::TempDir;

use super::super::common::*;

/// Tests CLI override of UI configuration from config file
#[test]
fn test_cli_ui_overrides_config_file() {
    let mut tester = PtyTester::new();
    let temp_config = TempConfig::init();

    let config_content = r#"
        [ui]
        ui_scale = 80

        [ui.input_bar]
        prompt = "config-prompt>"
        border_type = "plain"

        [ui.preview_panel]
        size = 40
        border_type = "thick"
    "#;

    temp_config.write_config(config_content).unwrap();

    // CLI should override all these UI settings
    let cmd = tv_with_args(&[
        "files",
        "--config-file",
        temp_config.config_file.to_str().unwrap(),
        "--cable-dir",
        DEFAULT_CABLE_DIR,
        "--ui-scale",
        "85",
        "--input-prompt",
        "cli-prompt>",
        "--preview-size",
        "70",
        "--input-border",
        "rounded",
        "--preview-border",
        "thick",
    ]);

    let mut child = tester.spawn_command_tui(cmd);

    // Verify the application starts with CLI overrides
    tester.assert_tui_frame_contains_all(&[
        "files",
        "cli-prompt>",
        // rounded border (input)
        "╭",
        // thick border (preview)
        "┏",
    ]);

    tester.send(&ctrl('c'));
    PtyTester::assert_exit_ok(&mut child, DEFAULT_DELAY);
}

/// Tests CLI overrides of channel-specific configuration
#[test]
fn test_cli_overrides_channel_source_and_preview() {
    let mut tester = PtyTester::new();
    let temp_config = TempConfig::init();

    let channel_content = r#"
        [metadata]
        name = "override-test"
        description = "Channel for override testing"

        [source]
        command = "echo 'channel-item-1'; echo 'channel-item-2'"

        [preview]
        command = "echo 'Channel preview: {}'"
    "#;
    temp_config
        .write_channel("override-test", channel_content)
        .unwrap();

    // CLI overrides both source and preview
    let cmd = tv_with_args(&[
        "override-test",
        "--cable-dir",
        temp_config.cable_dir.to_str().unwrap(),
        "--source-command",
        "echo 'cli-item-1'; echo 'cli-item-2'; echo 'cli-item-3'",
        "--preview-command",
        "echo 'CLI preview: {}'",
        "--preview-size",
        "60",
    ]);

    let mut child = tester.spawn_command_tui(cmd);

    // Should see CLI source command output instead of channel's
    tester.assert_tui_frame_contains_all(&[
        "override-test",
        "cli-item-1",
        "cli-item-2",
        "cli-item-3",
    ]);

    // Channel items should not appear
    tester.assert_not_tui_frame_contains("channel-item-1");

    tester.send(&ctrl('c'));
    PtyTester::assert_exit_ok(&mut child, DEFAULT_DELAY);
}

/// Tests CLI working directory parameter
#[test]
fn test_cli_working_directory_override() {
    let mut tester = PtyTester::new();
    let temp_dir = TempDir::new().unwrap();

    // Create a test file in the target directory
    std::fs::write(
        temp_dir.path().join("working-dir-test.txt"),
        "test content",
    )
    .unwrap();

    let cmd = tv_with_args(&[
        "files",
        "--cable-dir",
        DEFAULT_CABLE_DIR,
        "--input",
        "working-dir-test",
        "--take-1-fast",
        &temp_dir.path().to_string_lossy(), // PATH as positional argument
    ]);

    // Should exit with the found file
    let mut child = tester.spawn_command(cmd);
    // wait for completion so that the TUI doesn't interfere with
    // what we're capturing
    PtyTester::assert_exit_ok(&mut child, DEFAULT_DELAY);

    // Should find our test file in the target directory
    tester.assert_raw_output_contains("working-dir-test.txt");

    PtyTester::assert_exit_ok(&mut child, DEFAULT_DELAY);
}

/// Tests CLI input headers and footers override channel config
#[test]
fn test_cli_header_footer_overrides() {
    let mut tester = PtyTester::new();
    let temp_config = TempConfig::init();

    let channel_content = r#"
        [metadata]
        name = "header-test"
        description = "Header testing channel"

        [source]
        command = "echo 'header-item-1'; echo 'header-item-2'"

        [preview]
        command = "echo 'Channel preview: {}'"

        [ui.input_bar]
        header = "Channel Header"

        [ui.preview_panel]
        header = "Channel Preview Header"
        footer = "Channel Preview Footer"
    "#;
    temp_config
        .write_channel("header-test", channel_content)
        .unwrap();

    // CLI should override headers and footers
    let cmd = tv_with_args(&[
        "header-test",
        "--cable-dir",
        temp_config.cable_dir.to_str().unwrap(),
        "--input-header",
        "CLI Input Header",
        "--preview-header",
        "CLI Preview Header",
        "--preview-footer",
        "CLI Preview Footer",
    ]);

    let mut child = tester.spawn_command_tui(cmd);

    // Should show CLI headers instead of channel headers
    tester.assert_tui_frame_contains_all(&[
        "header-test",
        "header-item-1",
        "header-item-2",
        "CLI Preview Header",
        "CLI Preview Footer",
    ]);

    // Channel headers should not appear
    tester.assert_tui_frame_contains_none(&[
        "Channel Header",
        "Channel Preview Header",
        "Channel Preview Footer",
    ]);

    tester.send(&ctrl('c'));
    PtyTester::assert_exit_ok(&mut child, DEFAULT_DELAY);
}

/// Tests that empty CLI arguments don't override non-empty config values
#[test]
fn test_empty_cli_args_dont_override() {
    let mut tester = PtyTester::new();
    let temp_config = TempConfig::init();

    let config_content = r#"
        [ui.input_bar]
        prompt = "config-prompt>"
    "#;
    temp_config.write_config(config_content).unwrap();

    // Run without CLI overrides - config values should be used
    let cmd = tv_with_args(&[
        "files",
        "--config-file",
        temp_config.config_file.to_str().unwrap(),
        "--cable-dir",
        DEFAULT_CABLE_DIR,
    ]);

    let mut child = tester.spawn_command_tui(cmd);

    // Should show config values
    tester.assert_tui_frame_contains("config-prompt>");

    tester.send(&ctrl('c'));
    PtyTester::assert_exit_ok(&mut child, DEFAULT_DELAY);
}

/// Tests CLI override of input bar position
#[test]
fn test_cli_input_position_override() {
    let mut tester = PtyTester::new();

    let cmd = tv_with_args(&[
        "files",
        "--cable-dir",
        DEFAULT_CABLE_DIR,
        "--input-prompt",
        "position-prompt>",
        "--input-position",
        "bottom",
    ]);

    let mut child = tester.spawn_command_tui(cmd);

    let frame = tester.get_tui_frame();
    let prompt_index = frame
        .find("position-prompt>")
        .expect("Expected input prompt in frame");
    let results_index = frame
        .find("Results")
        .expect("Expected results header in frame");

    assert!(
        prompt_index > results_index,
        "Expected input bar below results when using --input-position=bottom.\nFrame:\n{}",
        frame
    );

    tester.send(&ctrl('c'));
    PtyTester::assert_exit_ok(&mut child, DEFAULT_DELAY);
}

#[test]
fn test_action_id_mismatch_validation_error() {
    let mut tester = PtyTester::new();
    let temp_config = TempConfig::init();

    // Create a channel with mismatched action reference
    let channel_content = r#"
        [metadata]
        name = "validation-test"
        description = "Channel for testing action validation"

        [source]
        command = "echo 'test-item-1'; echo 'test-item-2'"

        [keybindings]
        f12 = ["actions:edit_text", "toggle_preview"]

        [actions.edit]
        description = "Edit the selected file"
        command = "vi '{}'"
    "#;

    temp_config
        .write_channel("validation-test", channel_content)
        .unwrap();

    let cmd = tv_with_args(&[
        "validation-test",
        "--cable-dir",
        temp_config.cable_dir.to_str().unwrap(),
    ]);

    tester.spawn_command(cmd);

    // The validation should now panic with our message
    tester.assert_raw_output_contains(
        "Action 'actions:edit_text' referenced in keybinding not found in actions section",
    );
}
