use dirigent_archivist::{
    coordinator::Archivist,
    error::ArchivistBootError,
    registry::{ArchivesConfig, BackendRegistry},
};

fn parse(toml_src: &str) -> ArchivesConfig {
    toml::from_str(toml_src).unwrap()
}

#[tokio::test]
async fn boot_with_one_jsonl_archive() {
    let dir = tempfile::tempdir().unwrap();
    let cfg = parse(&format!(
        r#"
        [[archives]]
        name = "main"
        type = "jsonl"
        [archives.params]
        path = "{}"
        "#,
        dir.path().to_string_lossy().replace('\\', "/")
    ));
    let registry = BackendRegistry::with_jsonl();
    let _archivist = Archivist::from_config(cfg, &registry, None).await.unwrap();
}

#[tokio::test]
async fn boot_empty_config_is_ephemeral() {
    let cfg: ArchivesConfig = toml::from_str("").unwrap();
    let registry = BackendRegistry::with_jsonl();
    let archivist = Archivist::from_config(cfg, &registry, None).await.unwrap();
    let archives = archivist.list_archives().await.unwrap();
    assert!(archives.is_empty());
}

#[tokio::test]
async fn boot_unknown_type_errors() {
    let cfg = parse(
        r#"
        [[archives]]
        name = "x"
        type = "nope"
        [archives.params]
        "#,
    );
    let registry = BackendRegistry::with_jsonl();
    let result = Archivist::from_config(cfg, &registry, None).await;
    match result {
        Ok(_) => panic!("expected UnknownType error"),
        Err(err) => assert!(
            matches!(err, ArchivistBootError::UnknownType { .. }),
            "expected UnknownType, got {err:?}"
        ),
    }
}

#[tokio::test]
async fn boot_no_primary_errors() {
    let cfg = parse(
        r#"
        [[archives]]
        name = "mirror"
        type = "jsonl"
        failure_mode = "best_effort"
        [archives.params]
        path = "/tmp/whatever"
        "#,
    );
    let registry = BackendRegistry::with_jsonl();
    let result = Archivist::from_config(cfg, &registry, None).await;
    match result {
        Ok(_) => panic!("expected Validation error"),
        Err(err) => assert!(
            matches!(err, ArchivistBootError::Validation(_)),
            "expected Validation, got {err:?}"
        ),
    }
}

#[tokio::test]
async fn boot_duplicate_name_errors() {
    let dir = tempfile::tempdir().unwrap();
    let cfg = parse(&format!(
        r#"
        [[archives]]
        name = "main"
        type = "jsonl"
        [archives.params]
        path = "{p}"

        [[archives]]
        name = "main"
        type = "jsonl"
        [archives.params]
        path = "{p}"
        "#,
        p = dir.path().to_string_lossy().replace('\\', "/"),
    ));
    let registry = BackendRegistry::with_jsonl();
    let result = Archivist::from_config(cfg, &registry, None).await;
    match result {
        Ok(_) => panic!("expected Validation error"),
        Err(err) => assert!(
            matches!(err, ArchivistBootError::Validation(_)),
            "expected Validation, got {err:?}"
        ),
    }
}

#[test]
fn example_toml_parses() {
    // Load the full dirigent.toml.example and parse just the [[archives]]
    // section as `ArchivesConfig`. Confirms the example's archive syntax is
    // valid Phase 3 schema.
    let src = std::fs::read_to_string(
        std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
            .join("../../dirigent.toml.example"),
    )
    .expect("dirigent.toml.example present at workspace root");
    // Parse the whole file as a TOML value, then try to deserialize the
    // full document into `ArchivesConfig`. Any `archives` subtable gets picked up;
    // other top-level fields (connectors, matrix, ...) are ignored because
    // `ArchivesConfig` only has `entries: Vec<ArchiveConfig>` via
    // `#[serde(rename = "archives")]`.
    let cfg: ArchivesConfig =
        toml::from_str(&src).expect("ArchivesConfig from full example");
    cfg.validate().expect("example config validates");
    assert!(!cfg.entries.is_empty(), "example must declare at least one archive");
}
