#[cfg(test)]
mod tests {
    use cc_switch::cli::{Cli, Commands};
    use cc_switch::config::{ConfigStorage, Configuration, EnvironmentConfig};
    use clap::Parser;

    /// Helper function to create a test configuration
    fn create_test_config(alias: &str, token: &str, url: &str) -> Configuration {
        Configuration {
            alias_name: alias.to_string(),
            token: token.to_string(),
            url: url.to_string(),
            model: None,
            small_fast_model: None,
            max_thinking_tokens: None,
            api_timeout_ms: None,
            claude_code_disable_nonessential_traffic: None,
            anthropic_default_sonnet_model: None,
            anthropic_default_opus_model: None,
            anthropic_default_haiku_model: None,
            claude_code_experimental_agent_teams: None,
            claude_code_disable_1m_context: None,
            claude_code_subagent_model: None,
            claude_code_disable_nonstreaming_fallback: None,
            claude_code_effort_level: None,
        }
    }

    /// Helper function to create a full test configuration with all fields
    fn create_full_test_config(
        alias: &str,
        token: &str,
        url: &str,
        model: Option<&str>,
        small_fast_model: Option<&str>,
    ) -> Configuration {
        Configuration {
            alias_name: alias.to_string(),
            token: token.to_string(),
            url: url.to_string(),
            model: model.map(String::from),
            small_fast_model: small_fast_model.map(String::from),
            max_thinking_tokens: None,
            api_timeout_ms: None,
            claude_code_disable_nonessential_traffic: None,
            anthropic_default_sonnet_model: None,
            anthropic_default_opus_model: None,
            anthropic_default_haiku_model: None,
            claude_code_experimental_agent_teams: None,
            claude_code_disable_1m_context: None,
            claude_code_subagent_model: None,
            claude_code_disable_nonstreaming_fallback: None,
            claude_code_effort_level: None,
        }
    }

    // AddCommandParams Tests
    #[test]
    fn test_add_command_params_creation() {
        use cc_switch::config::types::AddCommandParams;

        let params = AddCommandParams {
            alias_name: "test".to_string(),
            token: Some("sk-ant-test".to_string()),
            url: Some("https://api.test.com".to_string()),
            model: None,
            small_fast_model: None,
            max_thinking_tokens: None,
            api_timeout_ms: None,
            claude_code_disable_nonessential_traffic: None,
            anthropic_default_sonnet_model: None,
            anthropic_default_opus_model: None,
            anthropic_default_haiku_model: None,
            claude_code_subagent_model: None,
            claude_code_disable_nonstreaming_fallback: None,
            claude_code_effort_level: None,
            force: false,
            interactive: false,
            token_arg: None,
            url_arg: None,
            from_file: None,
        };

        assert_eq!(params.alias_name, "test");
        assert_eq!(params.token, Some("sk-ant-test".to_string()));
        assert_eq!(params.url, Some("https://api.test.com".to_string()));
        assert!(!params.force);
        assert!(!params.interactive);
    }

    // CLI Command Parsing Tests
    #[test]
    fn test_cli_add_command_parsing() {
        let args = vec![
            "cc-switch",
            "add",
            "my-config",
            "sk-ant-test-token",
            "https://api.test.com",
        ];

        let cli = Cli::try_parse_from(args).expect("Should parse add command");

        match cli.command {
            Some(Commands::Add {
                alias_name,
                token_arg,
                url_arg,
                force,
                interactive,
                token,
                url,
                model,
                small_fast_model,
                max_thinking_tokens: _,
                api_timeout_ms: _,
                claude_code_disable_nonessential_traffic: _,
                anthropic_default_sonnet_model: _,
                anthropic_default_opus_model: _,
                anthropic_default_haiku_model: _,
                from_file: _,
                ..
            }) => {
                assert_eq!(alias_name, "my-config");
                assert_eq!(token_arg, Some("sk-ant-test-token".to_string()));
                assert_eq!(url_arg, Some("https://api.test.com".to_string()));
                assert!(!force);
                assert!(!interactive);
                assert_eq!(token, None);
                assert_eq!(url, None);
                assert_eq!(model, None);
                assert_eq!(small_fast_model, None);
            }
            _ => panic!("Expected Add command"),
        }
    }

    #[test]
    fn test_cli_add_command_with_flags() {
        let args = vec![
            "cc-switch",
            "add",
            "my-config",
            "-t",
            "sk-ant-flag-token",
            "-u",
            "https://flag.api.com",
            "--force",
            "--interactive",
        ];

        let cli = Cli::try_parse_from(args).expect("Should parse add command with flags");

        match cli.command {
            Some(Commands::Add {
                alias_name,
                token,
                url,
                force,
                interactive,
                token_arg,
                url_arg,
                model,
                small_fast_model,
                max_thinking_tokens: _,
                api_timeout_ms: _,
                claude_code_disable_nonessential_traffic: _,
                anthropic_default_sonnet_model: _,
                anthropic_default_opus_model: _,
                anthropic_default_haiku_model: _,
                from_file: _,
                ..
            }) => {
                assert_eq!(alias_name, "my-config");
                assert_eq!(token, Some("sk-ant-flag-token".to_string()));
                assert_eq!(url, Some("https://flag.api.com".to_string()));
                assert!(force);
                assert!(interactive);
                assert_eq!(token_arg, None);
                assert_eq!(url_arg, None);
                assert_eq!(model, None);
                assert_eq!(small_fast_model, None);
            }
            _ => panic!("Expected Add command"),
        }
    }

    #[test]
    fn test_cli_add_command_with_model_flags() {
        let args = vec![
            "cc-switch",
            "add",
            "model-config",
            "-t",
            "sk-ant-model-token",
            "-u",
            "https://model.api.com",
            "-m",
            "claude-3-5-sonnet-20241022",
            "--small-fast-model",
            "claude-3-haiku-20240307",
        ];

        let cli = Cli::try_parse_from(args).expect("Should parse add command with model flags");

        match cli.command {
            Some(Commands::Add {
                alias_name,
                token,
                url,
                model,
                small_fast_model,
                max_thinking_tokens: _,
                ..
            }) => {
                assert_eq!(alias_name, "model-config");
                assert_eq!(token, Some("sk-ant-model-token".to_string()));
                assert_eq!(url, Some("https://model.api.com".to_string()));
                assert_eq!(model, Some("claude-3-5-sonnet-20241022".to_string()));
                assert_eq!(
                    small_fast_model,
                    Some("claude-3-haiku-20240307".to_string())
                );
            }
            _ => panic!("Expected Add command"),
        }
    }

    #[test]
    fn test_cli_remove_command_single() {
        let args = vec!["cc-switch", "remove", "config-to-remove"];

        let cli = Cli::try_parse_from(args).expect("Should parse remove command");

        match cli.command {
            Some(Commands::Remove { alias_names }) => {
                assert_eq!(alias_names, vec!["config-to-remove"]);
            }
            _ => panic!("Expected Remove command"),
        }
    }

    #[test]
    fn test_cli_remove_command_multiple() {
        let args = vec!["cc-switch", "remove", "config1", "config2", "config3"];

        let cli = Cli::try_parse_from(args).expect("Should parse remove command");

        match cli.command {
            Some(Commands::Remove { alias_names }) => {
                assert_eq!(alias_names, vec!["config1", "config2", "config3"]);
            }
            _ => panic!("Expected Remove command"),
        }
    }

    #[test]
    fn test_cli_list_command() {
        let args = vec!["cc-switch", "list"];

        let cli = Cli::try_parse_from(args).expect("Should parse list command");

        match cli.command {
            Some(Commands::List { plain: _, .. }) => {
                // Test passes if we get List command
            }
            _ => panic!("Expected List command"),
        }
    }

    #[test]
    fn test_cli_default_command() {
        let args = vec!["cc-switch"];

        let cli = Cli::try_parse_from(args).expect("Should parse default command");

        match cli.command {
            None => {
                // Test passes - no command means enter interactive mode
            }
            _ => panic!("Expected no command for default behavior"),
        }
    }

    #[test]
    fn test_cli_completion_command() {
        let args = vec!["cc-switch", "completion", "fish"];

        let cli = Cli::try_parse_from(args).expect("Should parse completion command");

        match cli.command {
            Some(Commands::Completion { shell }) => {
                assert_eq!(shell, "fish");
            }
            _ => panic!("Expected Completion command"),
        }
    }

    #[test]
    fn test_cli_list_aliases_flag() {
        let args = vec!["cc-switch", "--list-aliases"];

        let cli = Cli::try_parse_from(args).expect("Should parse --list-aliases flag");

        assert!(cli.list_aliases, "Should have list_aliases flag set");
        assert!(
            cli.command.is_none(),
            "Should have no subcommand when using --list-aliases"
        );
    }

    #[test]
    fn test_cli_help_flag() {
        let result = Cli::try_parse_from(vec!["cc-switch", "--help"]);

        // Help flag causes early exit with help text
        assert!(result.is_err(), "Help flag should cause early exit");
    }

    #[test]
    fn test_cli_invalid_command() {
        let result = Cli::try_parse_from(vec!["cc-switch", "invalid-command"]);

        assert!(result.is_err(), "Invalid command should fail to parse");
    }

    // Integration Tests for Command Logic
    #[test]
    fn test_environment_config_generation() {
        let config = create_test_config("test", "sk-ant-test", "https://api.test.com");
        let env_config = EnvironmentConfig::from_config(&config);
        let env_tuples = env_config.as_env_tuples();

        assert_eq!(env_tuples.len(), 2);
        assert!(env_tuples.contains(&(
            "ANTHROPIC_AUTH_TOKEN".to_string(),
            "sk-ant-test".to_string()
        )));
        assert!(env_tuples.contains(&(
            "ANTHROPIC_BASE_URL".to_string(),
            "https://api.test.com".to_string()
        )));
    }

    #[test]
    fn test_environment_config_generation_with_models() {
        let config = create_full_test_config(
            "full-test",
            "sk-ant-full-test",
            "https://full-test.api.com",
            Some("claude-3-5-sonnet-20241022"),
            Some("claude-3-haiku-20240307"),
        );
        let env_config = EnvironmentConfig::from_config(&config);
        let env_tuples = env_config.as_env_tuples();

        assert_eq!(env_tuples.len(), 4);
        assert!(env_tuples.contains(&(
            "ANTHROPIC_AUTH_TOKEN".to_string(),
            "sk-ant-full-test".to_string()
        )));
        assert!(env_tuples.contains(&(
            "ANTHROPIC_BASE_URL".to_string(),
            "https://full-test.api.com".to_string()
        )));
        assert!(env_tuples.contains(&(
            "ANTHROPIC_MODEL".to_string(),
            "claude-3-5-sonnet-20241022".to_string()
        )));
        assert!(env_tuples.contains(&(
            "ANTHROPIC_SMALL_FAST_MODEL".to_string(),
            "claude-3-haiku-20240307".to_string()
        )));
    }

    #[test]
    fn test_empty_environment_config() {
        let env_config = EnvironmentConfig::empty();
        let env_tuples = env_config.as_env_tuples();

        assert!(env_tuples.is_empty());
    }

    // Error Handling Tests
    #[test]
    fn test_cli_add_missing_alias() {
        let result = Cli::try_parse_from(vec!["cc-switch", "add"]);

        assert!(result.is_err(), "Should fail when alias name is missing");
    }

    #[test]
    fn test_cli_remove_missing_alias() {
        let result = Cli::try_parse_from(vec!["cc-switch", "remove"]);

        assert!(
            result.is_err(),
            "Should fail when no alias names provided to remove"
        );
    }

    #[test]
    fn test_cli_completion_default_shell() {
        let result = Cli::try_parse_from(vec!["cc-switch", "completion"]);

        assert!(
            result.is_ok(),
            "Should succeed with default shell for completion command"
        );

        if let Ok(cli) = result {
            match cli.command {
                Some(Commands::Completion { shell }) => {
                    assert_eq!(shell, "fish", "Should default to fish shell");
                }
                _ => panic!("Expected Completion command"),
            }
        }
    }

    // Edge Cases Tests
    #[test]
    fn test_cli_empty_args() {
        let result = Cli::try_parse_from(vec!["cc-switch"]);

        // Should succeed but with no command (will trigger default behavior)
        assert!(result.is_ok(), "Empty args should parse successfully");
        let cli = result.unwrap();
        assert!(
            cli.command.is_none(),
            "Should have no command with empty args"
        );
        assert!(!cli.list_aliases, "Should not have list_aliases flag");
    }

    #[test]
    fn test_cli_with_special_characters_in_alias() {
        let args = vec![
            "cc-switch",
            "add",
            "test-config_123",
            "sk-ant-test",
            "https://api.test.com",
        ];

        let result = Cli::try_parse_from(args);
        assert!(
            result.is_ok(),
            "Should handle special characters in alias names"
        );

        if let Ok(cli) = result
            && let Some(Commands::Add { alias_name, .. }) = cli.command
        {
            assert_eq!(alias_name, "test-config_123");
        }
    }

    #[test]
    fn test_cli_unicode_in_arguments() {
        let args = vec![
            "cc-switch",
            "add",
            "测试-config",
            "sk-ant-测试",
            "https://αpi.测试.com",
        ];

        let result = Cli::try_parse_from(args);
        assert!(result.is_ok(), "Should handle Unicode in arguments");

        if let Ok(cli) = result
            && let Some(Commands::Add {
                alias_name,
                token_arg,
                url_arg,
                ..
            }) = cli.command
        {
            assert_eq!(alias_name, "测试-config");
            assert_eq!(token_arg, Some("sk-ant-测试".to_string()));
            assert_eq!(url_arg, Some("https://αpi.测试.com".to_string()));
        }
    }

    #[test]
    fn test_cli_very_long_arguments() {
        let long_alias = "a".repeat(1000);
        let long_token = format!("sk-ant-{}", "b".repeat(1000));
        let long_url = format!("https://{}com", "c".repeat(1000));

        let args = vec!["cc-switch", "add", &long_alias, &long_token, &long_url];

        let result = Cli::try_parse_from(args);
        assert!(result.is_ok(), "Should handle very long arguments");

        if let Ok(cli) = result
            && let Some(Commands::Add {
                alias_name,
                token_arg,
                url_arg,
                ..
            }) = cli.command
        {
            assert_eq!(alias_name.len(), 1000);
            assert_eq!(token_arg.as_ref().unwrap().len(), 1007); // "sk-ant-" + 1000
            assert_eq!(url_arg.as_ref().unwrap().len(), 1011); // "https://" + 1000 + "com"
        }
    }

    // Performance Tests (Basic)
    #[test]
    fn test_cli_parsing_performance() {
        let start = std::time::Instant::now();

        // Parse many commands to test performance
        for i in 0..1000 {
            let config_name = format!("config-{}", i);
            let token = format!("sk-ant-token-{}", i);
            let url = format!("https://api-{}.test.com", i);

            let args = vec!["cc-switch", "add", &config_name, &token, &url];

            let _ = Cli::try_parse_from(args);
        }

        let duration = start.elapsed();

        // Should complete within reasonable time (5 seconds is generous)
        assert!(
            duration.as_secs() < 5,
            "CLI parsing should be fast, took {:?}",
            duration
        );
    }

    // Configuration Storage Integration Tests
    #[test]
    fn test_storage_operations_integration() {
        let mut storage = ConfigStorage::default();

        // Add multiple configurations
        storage.add_configuration(create_test_config(
            "config1",
            "sk-ant-1",
            "https://api1.com",
        ));
        storage.add_configuration(create_test_config(
            "config2",
            "sk-ant-2",
            "https://api2.com",
        ));
        storage.add_configuration(create_test_config(
            "config3",
            "sk-ant-3",
            "https://api3.com",
        ));

        assert_eq!(storage.configurations.len(), 3);

        // Test retrieval
        let config1 = storage.get_configuration("config1").unwrap();
        assert_eq!(config1.token, "sk-ant-1");
        assert_eq!(config1.url, "https://api1.com");

        // Test removal
        assert!(storage.remove_configuration("config2"));
        assert_eq!(storage.configurations.len(), 2);
        assert!(storage.get_configuration("config2").is_none());

        // Test non-existent removal
        assert!(!storage.remove_configuration("nonexistent"));
        assert_eq!(storage.configurations.len(), 2);
    }

    #[test]
    fn test_cli_add_from_file_no_value() {
        let args = vec!["cc-switch", "add", "work", "--from-file"];
        let cli = Cli::try_parse_from(args).expect("Should parse --from-file with no value");
        match cli.command {
            Some(Commands::Add {
                alias_name,
                from_file,
                ..
            }) => {
                assert_eq!(alias_name, "work");
                assert_eq!(
                    from_file,
                    Some(None),
                    "expected Some(None) for bare --from-file"
                );
            }
            _ => panic!("Expected Add command"),
        }
    }

    #[test]
    fn test_cli_add_from_file_with_value() {
        let args = vec![
            "cc-switch",
            "add",
            "work",
            "--from-file",
            "/tmp/config.json",
        ];
        let cli = Cli::try_parse_from(args).expect("Should parse --from-file with path");
        match cli.command {
            Some(Commands::Add {
                alias_name,
                from_file,
                ..
            }) => {
                assert_eq!(alias_name, "work");
                assert_eq!(from_file, Some(Some("/tmp/config.json".to_string())));
            }
            _ => panic!("Expected Add command"),
        }
    }

    #[test]
    fn test_cli_add_alias_required() {
        let args = vec!["cc-switch", "add", "--from-file", "/tmp/config.json"];
        let result = Cli::try_parse_from(args);
        assert!(
            result.is_err(),
            "alias_name must be required even with --from-file"
        );
    }

    #[test]
    fn test_cli_add_from_file_default_path_branches_message() {
        // When `--from-file` is bare and the default path is missing, the
        // bail message should guide the user to run `claude` first.
        // When `--from-file <wrong-path>` is given, the message must NOT
        // mention "run `claude`" — the user clearly intended a specific file.
        //
        // We exercise this by running the binary against a non-existent HOME.

        use std::process::Command;

        // Build the binary (cargo test ensures it's already built, but we point
        // at the debug binary path directly).
        let bin = env!("CARGO_BIN_EXE_cc-switch");

        // Case A: bare `--from-file` with a HOME pointing at an empty dir.
        let tmp = tempfile::TempDir::new().expect("tempdir");
        let output_a = Command::new(bin)
            .env("HOME", tmp.path())
            .args(["add", "work", "--from-file"])
            .output()
            .expect("Should run cc-switch");
        let stderr_a = String::from_utf8_lossy(&output_a.stderr);
        assert!(
            !output_a.status.success(),
            "expected failure when default file missing"
        );
        assert!(
            stderr_a.contains("Default Claude config not found"),
            "default-branch message expected; got stderr: {}",
            stderr_a
        );
        assert!(
            stderr_a.contains("Run `claude` once"),
            "default-branch should advise running claude; got: {}",
            stderr_a
        );

        // Case B: explicit `--from-file /nonexistent/path.json`.
        let output_b = Command::new(bin)
            .env("HOME", tmp.path())
            .args([
                "add",
                "work",
                "--from-file",
                "/nonexistent/cc-switch-test.json",
            ])
            .output()
            .expect("Should run cc-switch");
        let stderr_b = String::from_utf8_lossy(&output_b.stderr);
        assert!(
            !output_b.status.success(),
            "expected failure when explicit path missing"
        );
        assert!(
            stderr_b.contains("Config file not found"),
            "explicit-branch message expected; got: {}",
            stderr_b
        );
        assert!(
            !stderr_b.contains("Run `claude`"),
            "explicit-branch must NOT advise running claude; got: {}",
            stderr_b
        );
    }
}
