use std::path::Path;

use indieweb::standards::vouch::DomainApprover;
use url::Url;

/// Load fixture file content from tests/fixtures/ directory
///
/// # Arguments
///
/// * `name` - The name of the fixture file (without .html extension)
///
/// # Returns
///
/// The content of the fixture file as a String
///
/// # Panics
///
/// Panics if the fixture file cannot be found or read
pub fn load_fixture(name: &str) -> String {
    let fixture_path = Path::new("tests/fixtures").join(format!("{}.html", name));
    std::fs::read_to_string(&fixture_path)
        .unwrap_or_else(|e| panic!("Failed to load fixture '{}': {}", name, e))
}

/// Create a test domain approver that approves a predefined set of domains
///
/// # Arguments
///
/// * `approved_domains` - A list of domain authorities to approve
///
/// # Returns
///
/// A boxed DomainApprover that checks against the approved domains
pub fn create_test_approver(approved_domains: Vec<String>) -> Box<dyn DomainApprover> {
    Box::new(TestApprover { approved_domains })
}

/// Mock a chat names HTTP response for testing
///
/// # Arguments
///
/// * `client` - The mockito server client to configure
/// * `path` - The URL path to mock
/// * `fixture_name` - The name of the fixture to use as response body
///
/// # Returns
///
/// The URL that was mocked
pub fn mock_chat_names_response(
    client: &mut indieweb::test::Client,
    path: &str,
    fixture_name: &str,
) -> Url {
    let fixture_content = load_fixture(fixture_name);
    let url = client.merge_into_url(path);

    // Create a mock response using the mock_server
    client.mock_server.mock("GET", path)
        .with_status(200)
        .with_header("content-type", "text/html")
        .with_body(fixture_content)
        .create();

    url
}

/// Test implementation of DomainApprover
struct TestApprover {
    approved_domains: Vec<String>,
}

#[async_trait::async_trait]
impl DomainApprover for TestApprover {
    async fn is_authority_approved(&self, authority: &str) -> Result<bool, indieweb::standards::vouch::VouchError> {
        Ok(self.approved_domains.contains(&authority.to_string()))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_load_fixture() {
        let content = load_fixture("chat_names_valid");
        assert!(content.contains("Alice"));
        assert!(content.contains("Bob"));
        assert!(content.contains("Charlie"));
    }

    #[test]
    fn test_load_fixture_nonexistent() {
        let result = std::panic::catch_unwind(|| {
            load_fixture("nonexistent_fixture");
        });
        assert!(result.is_err());
    }

    #[tokio::test]
    async fn test_create_test_approver() {
        let approver = create_test_approver(vec![
            "https://trusted.example.com".to_string(),
            "https://semi-trusted.example.com".to_string(),
        ]);

        assert!(approver.is_authority_approved("https://trusted.example.com").await.unwrap());
        assert!(approver.is_authority_approved("https://semi-trusted.example.com").await.unwrap());
        assert!(!approver.is_authority_approved("https://unknown.example.com").await.unwrap());
    }

    #[test]
    fn test_create_test_approver_empty() {
        let approver = create_test_approver(vec![]);
        // Note: This is a sync test, so we can't call async methods here
        // Just verify it was created successfully
        let _ = approver;
    }
}
