//! Test that connects the current (latest) Rust SDK sync against the oldest supported Ditto version
//!
//! Counterpart, which inserts the doc and listens on TCP is in `/tools/oldest-sdk-test`.

#![allow(clippy::disallowed_macros)]
#![allow(deprecated)] // TODO: Update querybuilder usage to DQL
use std::{env, error::Error, fs::File, io::Read, process, str::FromStr, thread, time::Duration};

use dittolive_ditto::prelude::*;
use serde::Deserialize;

#[derive(Deserialize)]
struct MyDoc {
    _id: String,
    att: DittoAttachmentToken,
}

const EXAMPLE_ATTACHMENT_DATA: &[u8] = b"Some data";

#[allow(deprecated)] // TODO: Update querybuilder usage to DQL
fn main() -> Result<(), Box<dyn Error>> {
    let mut args = env::args();
    let _app_name = args.next();
    let app_id = args.next().expect("expected App ID as first parameter");
    let doc_id = args
        .next()
        .expect("expected target document ID as second parameter");
    let connect_port: u16 = args
        .next()
        .expect("expected connect port as third parameter")
        .parse()
        .expect("expected port to be a valid u16");

    let ditto = Ditto::builder()
        .with_temp_dir()
        .with_minimum_log_level(LogLevel::Debug)
        .with_identity(|ditto_root| {
            let app_id = AppId::from_str(&app_id)?;
            OfflinePlayground::new(ditto_root, app_id)
        })?
        .with_transport_config(|_identity| {
            let mut transport_config = TransportConfig::new();
            let other_peer = format!("127.0.0.1:{}", connect_port);
            transport_config.connect.tcp_servers.insert(other_peer);
            transport_config
        })?
        .build()?;
    ditto.set_license_from_env("DITTO_LICENSE")?;
    ditto.sync().start()?;

    let collection = ditto.store().collection("test_coll").unwrap();
    println!("old_sync_test looking for doc_id {}", doc_id);
    let doc_id = DocumentId::new(&doc_id).unwrap();
    let _sub = collection.find_by_id(doc_id.clone()).subscribe();
    let _obs =
        collection
            .find_by_id(doc_id)
            .observe_local(move |maybe_doc: Option<BoxedDocument>, _| {
                if let Some(doc) = maybe_doc {
                    println!("old_sync_test found expected doc");
                    let doc = doc.typed::<MyDoc>().unwrap();
                    let _ = ditto
                        .store()
                        .fetch_attachment(doc.att, |event| {
                            if let DittoAttachmentFetchEvent::Completed { attachment: att } = event
                            {
                                let mut file = File::open(att.path()).unwrap();
                                let mut buf = vec![];
                                file.read_to_end(&mut buf).unwrap();
                                assert_eq!(buf, EXAMPLE_ATTACHMENT_DATA);
                                println!("old_sync_test found expected attachment");
                                process::exit(0);
                            }
                        })
                        .unwrap();
                }
            });

    // Should succeed within a reasonable time
    thread::sleep(Duration::from_secs(30));
    Err("timed out".into())
}
