#[cfg(test)]
mod webui_integration_tests {
    use crate::address::{NetLocation, NetLocationPortRange, NetLocationMask};
    use crate::config::{
        BindLocation, ClientConfig, Config, NamedPem, PemSource,
        RuleActionConfig, RuleConfig, ServerConfig, ServerProxyConfig,
        Transport, ClientProxyConfig, TcpConfig, ServerQuicConfig,
        ConfigSelection, ShadowsocksConfig,
    };
    use crate::option_util::{OneOrSome, NoneOrSome, NoneOrOne};
    use crate::webui::handlers::*;
    use crate::webui::AppState;
    use axum::extract::{Path, State};
    use axum::response::Json;
    use tempfile::NamedTempFile;

    // Helper function to create a test state
    async fn create_test_state() -> (AppState, NamedTempFile) {
        let temp_file = NamedTempFile::new().unwrap();
        let state = AppState::new(temp_file.path().to_path_buf());
        // Initialize with empty configs
        let mut configs = state.configs.write().await;
        configs.clear();
        drop(configs);
        (state, temp_file)
    }

    #[tokio::test]
    async fn test_get_empty_config() {
        let (state, _temp_file) = create_test_state().await;

        let result = get_config(State(state)).await.unwrap();
        assert!(result.0.success);
        
        if let Some(data) = result.0.data {
            assert!(data.servers.is_empty());
            assert!(data.client_groups.is_empty());
            assert!(data.rule_groups.is_empty());
            assert!(data.named_pems.is_empty());
        } else {
            panic!("Expected config data");
        }
    }

    #[tokio::test]
    async fn test_create_named_pem() {
        let (state, _temp_file) = create_test_state().await;

        let pem_config = NamedPem {
            pem: "test-cert".to_string(),
            source: PemSource::Data("-----BEGIN CERTIFICATE-----\nMIIBkTCB+wIJAKHHIgKwY4u0MA0GCSqGSIb3DQEBBQUAMA==\n-----END CERTIFICATE-----".to_string()),
        };

        let result = create_named_pem(State(state.clone()), Json(pem_config))
            .await
            .unwrap();
        assert!(result.0.success);

        // Verify it was created
        let configs = state.configs.read().await;
        assert_eq!(configs.len(), 1);
        match &configs[0] {
            Config::NamedPem(pem) => {
                assert_eq!(pem.pem, "test-cert");
                match &pem.source {
                    PemSource::Data(data) => {
                        assert!(data.contains("-----BEGIN CERTIFICATE-----"));
                    }
                    _ => panic!("Expected inline data"),
                }
            }
            _ => panic!("Expected named PEM config"),
        }
    }

    #[tokio::test]
    async fn test_create_server() {
        let (state, _temp_file) = create_test_state().await;

        let server_config = ServerConfig {
            bind_location: BindLocation::Address(NetLocationPortRange::from_str("0.0.0.0:8080").unwrap()),
            protocol: ServerProxyConfig::Http {
                username: Some("user".to_string()),
                password: Some("pass".to_string()),
            },
            transport: Transport::Tcp,
            tcp_settings: Some(TcpConfig {
                no_delay: true,
            }),
            quic_settings: None,
            rules: NoneOrSome::Unspecified,
        };

        let result = create_server(State(state.clone()), Json(server_config))
            .await
            .unwrap();
        assert!(result.0.success);

        // Verify it was created
        let configs = state.configs.read().await;
        assert_eq!(configs.len(), 1);
        match &configs[0] {
            Config::Server(server) => {
                match &server.bind_location {
                    BindLocation::Address(addr) => {
                        assert_eq!(addr.to_string(), "0.0.0.0:8080");
                    }
                    _ => panic!("Expected address bind location"),
                }
            }
            _ => panic!("Expected server config"),
        }
    }

    #[tokio::test]
    async fn test_update_server() {
        let (state, _temp_file) = create_test_state().await;

        // Create a server first
        let server_config = ServerConfig {
            bind_location: BindLocation::Address(NetLocationPortRange::from_str("0.0.0.0:8080").unwrap()),
            protocol: ServerProxyConfig::Http {
                username: None,
                password: None,
            },
            transport: Transport::Tcp,
            tcp_settings: None,
            quic_settings: None,
            rules: NoneOrSome::Unspecified,
        };

        create_server(State(state.clone()), Json(server_config))
            .await
            .unwrap();

        // Update the server
        let updated_config = ServerConfig {
            bind_location: BindLocation::Address(NetLocationPortRange::from_str("0.0.0.0:8080").unwrap()),
            protocol: ServerProxyConfig::Socks {
                username: Some("newuser".to_string()),
                password: None,
            },
            transport: Transport::Tcp,
            tcp_settings: None,
            quic_settings: None,
            rules: NoneOrSome::Unspecified,
        };

        let result = update_server(
            State(state.clone()),
            Path("0.0.0.0:8080".to_string()),
            Json(updated_config),
        )
        .await
        .unwrap();
        assert!(result.0.success);

        // Verify it was updated
        let configs = state.configs.read().await;
        assert_eq!(configs.len(), 1);
    }

    #[tokio::test]
    async fn test_delete_server() {
        let (state, _temp_file) = create_test_state().await;

        // Create a server first
        let server_config = ServerConfig {
            bind_location: BindLocation::Address(NetLocationPortRange::from_str("0.0.0.0:8080").unwrap()),
            protocol: ServerProxyConfig::Http {
                username: None,
                password: None,
            },
            transport: Transport::Tcp,
            tcp_settings: None,
            quic_settings: None,
            rules: NoneOrSome::Unspecified,
        };

        create_server(State(state.clone()), Json(server_config))
            .await
            .unwrap();

        // Delete the server
        let result = delete_server(State(state.clone()), Path("0.0.0.0:8080".to_string()))
            .await
            .unwrap();
        assert!(result.0.success);

        // Verify it was deleted
        let configs = state.configs.read().await;
        assert!(configs.is_empty());
    }

    #[tokio::test]
    async fn test_client_group_crud() {
        let (state, _temp_file) = create_test_state().await;

        // Create a client group
        let group_config = ClientGroupConfig {
            name: "my-proxies".to_string(),
            proxies: vec![
                ClientConfig {
                    bind_interface: NoneOrOne::Unspecified,
                    address: NetLocation::from_str("proxy.example.com:1080", None).unwrap(),
                    protocol: ClientProxyConfig::Socks {
                        username: Some("user".to_string()),
                        password: Some("pass".to_string()),
                    },
                    transport: Transport::Tcp,
                    tcp_settings: None,
                    quic_settings: None,
                },
            ],
        };

        let result = create_client_group(State(state.clone()), Json(group_config))
            .await
            .unwrap();
        assert!(result.0.success);

        // Verify it was created
        let configs = state.configs.read().await;
        assert_eq!(configs.len(), 1);
        match &configs[0] {
            Config::ClientConfigGroup(group) => {
                assert_eq!(group.client_group, "my-proxies");
            }
            _ => panic!("Expected client group config"),
        }
        drop(configs); // Drop the read lock before acquiring write lock

        // Delete it
        let result = delete_client_group(State(state.clone()), Path("my-proxies".to_string()))
            .await
            .unwrap();
        assert!(result.0.success);

        // Verify it was deleted
        let configs = state.configs.read().await;
        assert!(configs.is_empty());
    }

    #[tokio::test]
    async fn test_rule_group_crud() {
        let (state, _temp_file) = create_test_state().await;

        // Create a rule group
        let rule_config = RuleGroupConfig {
            name: "custom-rules".to_string(),
            rules: vec![
                RuleConfig {
                    masks: OneOrSome::Some(vec![
                        NetLocationMask::from("192.168.1.0/24").unwrap(),
                        NetLocationMask::from("10.0.0.0/8").unwrap()
                    ]),
                    action: RuleActionConfig::Allow {
                        override_address: None,
                        client_proxies: OneOrSome::One(ConfigSelection::GroupName("direct".to_string())),
                    },
                },
                RuleConfig {
                    masks: OneOrSome::One(NetLocationMask::from("0.0.0.0/0").unwrap()),
                    action: RuleActionConfig::Block,
                },
            ],
        };

        let result = create_rule_group(State(state.clone()), Json(rule_config))
            .await
            .unwrap();
        assert!(result.0.success);

        // Verify it was created
        let configs = state.configs.read().await;
        assert_eq!(configs.len(), 1);
        match &configs[0] {
            Config::RuleConfigGroup(group) => {
                assert_eq!(group.rule_group, "custom-rules");
            }
            _ => panic!("Expected rule group config"),
        }
    }

    #[tokio::test]
    async fn test_import_export() {
        let (state, _temp_file) = create_test_state().await;

        // Create some configuration
        let pem_config = NamedPem {
            pem: "test-pem".to_string(),
            source: PemSource::Data("-----BEGIN CERTIFICATE-----\ntest\n-----END CERTIFICATE-----".to_string()),
        };
        create_named_pem(State(state.clone()), Json(pem_config))
            .await
            .unwrap();

        let server_config = ServerConfig {
            bind_location: BindLocation::Address(NetLocationPortRange::from_str("0.0.0.0:8080").unwrap()),
            protocol: ServerProxyConfig::Http {
                username: None,
                password: None,
            },
            transport: Transport::Tcp,
            tcp_settings: None,
            quic_settings: None,
            rules: NoneOrSome::Unspecified,
        };
        create_server(State(state.clone()), Json(server_config))
            .await
            .unwrap();

        // Export configuration
        let yaml_content = export_config(State(state.clone())).await.unwrap();
        assert!(yaml_content.contains("pem: test-pem"));
        assert!(yaml_content.contains("address: 0.0.0.0:8080"));

        // Clear configuration
        let empty_config = ConfigResponse {
            servers: vec![],
            client_groups: vec![],
            rule_groups: vec![],
            named_pems: vec![],
        };
        update_config(State(state.clone()), Json(empty_config))
            .await
            .unwrap();

        // Verify it's empty
        let configs = state.configs.read().await;
        assert!(configs.is_empty());
        drop(configs);

        // Import the exported configuration
        let result = import_config(State(state.clone()), yaml_content)
            .await
            .unwrap();
        assert!(result.0.success);

        // Verify it was imported
        let configs = state.configs.read().await;
        assert_eq!(configs.len(), 2); // PEM and server
    }

    #[tokio::test]
    async fn test_validation() {
        let (_state, _temp_file) = create_test_state().await;

        // Create invalid configuration (missing required fields for shadowsocks)
        let invalid_config = ValidationRequest {
            servers: Some(vec![ServerConfig {
                bind_location: BindLocation::Address(NetLocationPortRange::from_str("0.0.0.0:8080").unwrap()),
                protocol: ServerProxyConfig::Shadowsocks(ShadowsocksConfig {
                    cipher: "aes-256-gcm".to_string(),
                    password: "".to_string(), // Invalid empty password
                }),
                transport: Transport::Tcp,
                tcp_settings: None,
                quic_settings: None,
                rules: NoneOrSome::Unspecified,
            }]),
            client_groups: None,
            rule_groups: None,
        };

        let result = validate_config(Json(invalid_config))
            .await
            .unwrap();
        // Note: Empty password might actually be valid, so we check the response structure
        assert!(result.0.valid || !result.0.errors.is_empty());
    }

    #[tokio::test]
    async fn test_duplicate_prevention() {
        let (state, _temp_file) = create_test_state().await;

        // Create a named PEM
        let pem_config = NamedPem {
            pem: "duplicate-test".to_string(),
            source: PemSource::Data("test".to_string()),
        };
        create_named_pem(State(state.clone()), Json(pem_config.clone()))
            .await
            .unwrap();

        // Try to create another with the same name
        let result = create_named_pem(State(state.clone()), Json(pem_config))
            .await
            .unwrap();
        assert!(!result.0.success);
        assert!(result.0.error.unwrap().contains("already exists"));
    }

    #[tokio::test]
    async fn test_complex_server_configuration() {
        let (state, _temp_file) = create_test_state().await;

        // Create named PEMs for QUIC
        let pem_config = NamedPem {
            pem: "quic-cert".to_string(),
            source: PemSource::Data("-----BEGIN CERTIFICATE-----\ntest cert\n-----END CERTIFICATE-----\n-----BEGIN PRIVATE KEY-----\ntest key\n-----END PRIVATE KEY-----".to_string()),
        };
        create_named_pem(State(state.clone()), Json(pem_config))
            .await
            .unwrap();

        // Create client group for rules
        let client_group = ClientGroupConfig {
            name: "upstream-proxies".to_string(),
            proxies: vec![ClientConfig {
                bind_interface: NoneOrOne::Unspecified,
                address: NetLocation::from_str("unspecified:0", None).unwrap(),
                protocol: ClientProxyConfig::Direct,
                transport: Transport::Tcp,
                tcp_settings: None,
                quic_settings: None,
            }],
        };
        create_client_group(State(state.clone()), Json(client_group))
            .await
            .unwrap();

        // Create rule group
        let rule_group = RuleGroupConfig {
            name: "custom-rules".to_string(),
            rules: vec![RuleConfig {
                masks: OneOrSome::One(NetLocationMask::from("0.0.0.0/0").unwrap()),
                action: RuleActionConfig::Allow {
                    override_address: None,
                    client_proxies: OneOrSome::One(ConfigSelection::GroupName("upstream-proxies".to_string())),
                },
            }],
        };
        create_rule_group(State(state.clone()), Json(rule_group))
            .await
            .unwrap();

        // Create QUIC server with all settings
        let server_config = ServerConfig {
            bind_location: BindLocation::Address(NetLocationPortRange::from_str("0.0.0.0:443").unwrap()),
            protocol: ServerProxyConfig::Trojan {
                password: "secure-password".to_string(),
                shadowsocks: Some(ShadowsocksConfig {
                    cipher: "aes-256-gcm".to_string(),
                    password: "ss-password".to_string(),
                }),
            },
            transport: Transport::Quic,
            tcp_settings: None,
            quic_settings: Some(ServerQuicConfig {
                cert: "quic-cert".to_string(),
                key: "quic-cert".to_string(),
                alpn_protocols: NoneOrSome::Some(vec!["h3".to_string(), "h3-29".to_string()]),
                num_endpoints: 4,
                client_ca_certs: NoneOrSome::Unspecified,
                client_fingerprints: NoneOrSome::Unspecified,
            }),
            rules: NoneOrSome::Some(vec![ConfigSelection::GroupName("custom-rules".to_string())]),
        };

        let result = create_server(State(state.clone()), Json(server_config))
            .await
            .unwrap();
        assert!(result.0.success);

        // Verify complete configuration
        let configs = state.configs.read().await;
        assert_eq!(configs.len(), 4); // PEM, client group, rule group, server
    }
}