use super::*;
use std::path::Path;

#[test]
fn session_display_names_round_trip() {
    let path = std::env::temp_dir().join(format!(
        "tidev-session-store-{}.sqlite3",
        uuid::Uuid::new_v4()
    ));

    {
        let store = SessionStore::open(&path).expect("store should open");
        let session_id = uuid::Uuid::new_v4();

        let record = store
            .create_session(
                session_id,
                Path::new("/tmp/workspace"),
                "deepseek",
                "DeepSeek",
                "deepseek-v4-flash",
                "DeepSeek-V4-Flash",
                "Untitled session",
            )
            .expect("session should be created");

        assert_eq!(record.provider_id, "deepseek");
        assert_eq!(record.provider_display_name, "DeepSeek");
        assert_eq!(record.model_id, "deepseek-v4-flash");
        assert_eq!(record.model_display_name, "DeepSeek-V4-Flash");
        assert_eq!(record.workspace_root, "/tmp/workspace");
        assert_eq!(record.context_summary, None);
        assert_eq!(record.context_retained_from, 0);

        let loaded = store
            .load_session_record(session_id)
            .expect("session should load")
            .expect("session should exist");

        assert_eq!(loaded.provider_display_name, "DeepSeek");
        assert_eq!(loaded.model_display_name, "DeepSeek-V4-Flash");
        assert_eq!(loaded.workspace_root, "/tmp/workspace");
        assert_eq!(loaded.context_summary, None);
        assert_eq!(loaded.context_retained_from, 0);

        let conversation = store
            .load_conversation(session_id)
            .expect("conversation should load")
            .expect("conversation should exist");

        assert_eq!(conversation.provider_display_name, "DeepSeek");
        assert_eq!(conversation.model_display_name, "DeepSeek-V4-Flash");
        assert_eq!(conversation.workspace_root, "/tmp/workspace");
        assert_eq!(conversation.context_summary, None);
        assert_eq!(conversation.context_retained_from, 0);
    }

    let _ = std::fs::remove_file(path);
}

#[test]
fn context_state_round_trip() {
    let path = std::env::temp_dir().join(format!(
        "tidev-session-store-context-{}.sqlite3",
        uuid::Uuid::new_v4()
    ));

    {
        let store = SessionStore::open(&path).expect("store should open");
        let session_id = uuid::Uuid::new_v4();

        store
            .create_session(
                session_id,
                Path::new("/tmp/workspace"),
                "openai",
                "OpenAI",
                "gpt-4o",
                "GPT-4o",
                "Untitled session",
            )
            .expect("session should be created");

        store
            .update_session_context_state(
                session_id,
                Some("Context summary for continuation:\n- files: src/main.rs"),
                7,
            )
            .expect("context state should update");

        let record = store
            .load_session_record(session_id)
            .expect("session should load")
            .expect("session should exist");

        assert_eq!(
            record.context_summary.as_deref(),
            Some("Context summary for continuation:\n- files: src/main.rs")
        );
        assert_eq!(record.context_retained_from, 7);

        let conversation = store
            .load_conversation(session_id)
            .expect("conversation should load")
            .expect("conversation should exist");

        assert_eq!(
            conversation.context_summary.as_deref(),
            Some("Context summary for continuation:\n- files: src/main.rs")
        );
        assert_eq!(conversation.context_retained_from, 7);
    }

    let _ = std::fs::remove_file(path);
}

#[test]
fn child_session_round_trip_records_parent() {
    let path = std::env::temp_dir().join(format!(
        "tidev-session-store-child-{}.sqlite3",
        uuid::Uuid::new_v4()
    ));

    {
        let store = SessionStore::open(&path).expect("store should open");
        let parent_session_id = uuid::Uuid::new_v4();
        let child_session_id = uuid::Uuid::new_v4();

        store
            .create_session(
                parent_session_id,
                Path::new("/tmp/workspace"),
                "openai",
                "OpenAI",
                "gpt-4o",
                "GPT-4o",
                "Parent",
            )
            .expect("parent session should be created");

        let child_record = store
            .create_session_with_parent(
                child_session_id,
                parent_session_id,
                Path::new("/tmp/workspace"),
                "openai",
                "OpenAI",
                "gpt-4o",
                "GPT-4o",
                "Task: Child",
            )
            .expect("child session should be created");

        assert_eq!(child_record.parent_session_id, Some(parent_session_id));

        let loaded = store
            .load_session_record(child_session_id)
            .expect("child session should load")
            .expect("child session should exist");
        assert_eq!(loaded.parent_session_id, Some(parent_session_id));

        let children = store
            .load_child_sessions(parent_session_id)
            .expect("child sessions should load");
        assert_eq!(children.len(), 1);
        assert_eq!(children[0].session_id, child_session_id);
        assert_eq!(children[0].parent_session_id, Some(parent_session_id));
    }

    let _ = std::fs::remove_file(path);
}

#[test]
fn tool_event_output_round_trip() {
    let path = std::env::temp_dir().join(format!(
        "tidev-session-store-tool-output-{}.sqlite3",
        uuid::Uuid::new_v4()
    ));

    {
        let store = SessionStore::open(&path).expect("store should open");
        let session_id = uuid::Uuid::new_v4();
        let message_id = uuid::Uuid::new_v4();

        store
            .create_session(
                session_id,
                Path::new("/tmp/workspace"),
                "openai",
                "OpenAI",
                "gpt-4o",
                "GPT-4o",
                "Untitled session",
            )
            .expect("session should be created");

        store
            .append_tool_event(
                session_id,
                message_id,
                "grep",
                r#"{"pattern":"foo"}"#,
                "match-one\nmatch-two",
            )
            .expect("tool event should append");

        let output = store
            .load_tool_event_output(session_id, message_id)
            .expect("tool output should load")
            .expect("tool output should exist");

        assert_eq!(output, "match-one\nmatch-two");
    }

    let _ = std::fs::remove_file(path);
}

#[test]
fn copy_tool_permissions_inherits_parent_permissions() {
    let path = std::env::temp_dir().join(format!(
        "tidev-session-store-permissions-{}.sqlite3",
        uuid::Uuid::new_v4()
    ));

    {
        let store = SessionStore::open(&path).expect("store should open");
        let parent_session_id = uuid::Uuid::new_v4();
        let child_session_id = uuid::Uuid::new_v4();

        store
            .create_session(
                parent_session_id,
                Path::new("/tmp/workspace"),
                "openai",
                "OpenAI",
                "gpt-4o",
                "GPT-4o",
                "Parent",
            )
            .expect("parent session should be created");

        store
            .create_session_with_parent(
                child_session_id,
                parent_session_id,
                Path::new("/tmp/workspace"),
                "openai",
                "OpenAI",
                "gpt-4o",
                "GPT-4o",
                "Task: Child",
            )
            .expect("child session should be created");

        store
            .remember_tool_permission(parent_session_id, "bash", true)
            .expect("permission should be recorded");
        store
            .remember_tool_permission(parent_session_id, "read", false)
            .expect("permission should be recorded");

        store
            .copy_tool_permissions(parent_session_id, child_session_id)
            .expect("permissions should be copied");

        assert_eq!(
            store
                .load_tool_permission(child_session_id, "bash")
                .expect("child permission should load"),
            Some(true)
        );
        assert_eq!(
            store
                .load_tool_permission(child_session_id, "read")
                .expect("child permission should load"),
            Some(false)
        );
    }

    let _ = std::fs::remove_file(path);
}

#[test]
fn child_sessions_are_hidden_from_session_lists() {
    let path = std::env::temp_dir().join(format!(
        "tidev-session-store-visibility-{}.sqlite3",
        uuid::Uuid::new_v4()
    ));

    {
        let store = SessionStore::open(&path).expect("store should open");
        let workspace_root = Path::new("/tmp/workspace");
        let parent_session_id = uuid::Uuid::new_v4();
        let child_session_id = uuid::Uuid::new_v4();

        store
            .create_session(
                parent_session_id,
                workspace_root,
                "openai",
                "OpenAI",
                "gpt-4o",
                "GPT-4o",
                "Parent",
            )
            .expect("parent session should be created");

        std::thread::sleep(std::time::Duration::from_millis(2));

        store
            .create_session_with_parent(
                child_session_id,
                parent_session_id,
                workspace_root,
                "openai",
                "OpenAI",
                "gpt-4o",
                "GPT-4o",
                "Task: Child",
            )
            .expect("child session should be created");

        let workspace_sessions = store
            .load_sessions_for_workspace(workspace_root)
            .expect("workspace sessions should load");
        assert_eq!(workspace_sessions.len(), 1);
        assert_eq!(workspace_sessions[0].session_id, parent_session_id);

        let all_sessions = store.load_all_sessions().expect("all sessions should load");
        assert_eq!(all_sessions.len(), 1);
        assert_eq!(all_sessions[0].session_id, parent_session_id);

        let latest_session = store
            .load_latest_session()
            .expect("latest session should load")
            .expect("latest session should exist");
        assert_eq!(latest_session.session_id, parent_session_id);
    }

    let _ = std::fs::remove_file(path);
}

#[test]
fn workspace_session_listing_is_scoped_and_sorted() {
    let path = std::env::temp_dir().join(format!(
        "tidev-session-store-list-{}.sqlite3",
        uuid::Uuid::new_v4()
    ));

    {
        let store = SessionStore::open(&path).expect("store should open");
        let shared_root = Path::new("/tmp/tidev-workspace-a");
        let other_root = Path::new("/tmp/tidev-workspace-b");

        let first = store
            .create_session(
                uuid::Uuid::new_v4(),
                shared_root,
                "openai",
                "OpenAI",
                "gpt-4o",
                "GPT-4o",
                "First",
            )
            .expect("first session should be created");

        std::thread::sleep(std::time::Duration::from_millis(2));

        let second = store
            .create_session(
                uuid::Uuid::new_v4(),
                shared_root,
                "openai",
                "OpenAI",
                "gpt-4o-mini",
                "GPT-4o mini",
                "Second",
            )
            .expect("second session should be created");

        store
            .create_session(
                uuid::Uuid::new_v4(),
                other_root,
                "anthropic",
                "Anthropic",
                "claude",
                "Claude",
                "Other",
            )
            .expect("other session should be created");

        let sessions = store
            .load_sessions_for_workspace(shared_root)
            .expect("sessions should load");

        assert_eq!(sessions.len(), 2);
        assert_eq!(sessions[0].session_id, second.session_id);
        assert_eq!(sessions[1].session_id, first.session_id);
    }

    let _ = std::fs::remove_file(path);
}

#[test]
fn revert_marker_round_trips() {
    let path = std::env::temp_dir().join(format!(
        "tidev-session-store-revert-{}.sqlite3",
        uuid::Uuid::new_v4()
    ));

    {
        let store = SessionStore::open(&path).expect("store should open");
        let session_id = uuid::Uuid::new_v4();
        let message_id = uuid::Uuid::new_v4();

        store
            .create_session(
                session_id,
                Path::new("/workspace"),
                "deepseek",
                "DeepSeek",
                "deepseek-v4-flash",
                "DeepSeek-V4-Flash",
                "Untitled session",
            )
            .expect("session should be created");

        assert_eq!(
            store
                .load_revert_message_id(session_id)
                .expect("revert should load"),
            None
        );

        store
            .set_revert_message_id(session_id, Some(message_id), None)
            .expect("revert should save");

        assert_eq!(
            store
                .load_revert_message_id(session_id)
                .expect("revert should load"),
            Some(message_id)
        );

        let conversation = store
            .load_conversation(session_id)
            .expect("conversation should load")
            .expect("conversation should exist");

        assert_eq!(conversation.revert_message_id, Some(message_id));

        store
            .clear_revert_message_id(session_id)
            .expect("revert should clear");

        assert_eq!(
            store
                .load_revert_message_id(session_id)
                .expect("revert should load"),
            None
        );
    }

    let _ = std::fs::remove_file(path);
}

#[test]
fn gateway_chat_session_mapping_round_trip() {
    let path = std::env::temp_dir().join(format!(
        "tidev-session-store-gateway-map-{}.sqlite3",
        uuid::Uuid::new_v4()
    ));

    {
        let store = SessionStore::open(&path).expect("store should open");
        let first_session = uuid::Uuid::new_v4();
        let second_session = uuid::Uuid::new_v4();
        let chat_key = "-100123456:42";

        store
            .create_session(
                first_session,
                Path::new("/workspace"),
                "openai",
                "OpenAI",
                "gpt-4o-mini",
                "GPT-4o mini",
                "First",
            )
            .expect("first session should be created");

        store
            .set_gateway_chat_session("telegram", chat_key, first_session)
            .expect("mapping should save");

        assert_eq!(
            store
                .load_gateway_chat_session("telegram", chat_key)
                .expect("mapping should load"),
            Some(first_session)
        );

        store
            .create_session(
                second_session,
                Path::new("/workspace"),
                "openai",
                "OpenAI",
                "gpt-4o-mini",
                "GPT-4o mini",
                "Second",
            )
            .expect("second session should be created");

        store
            .set_gateway_chat_session("telegram", chat_key, second_session)
            .expect("mapping should update");

        assert_eq!(
            store
                .load_gateway_chat_session("telegram", chat_key)
                .expect("updated mapping should load"),
            Some(second_session)
        );

        store
            .clear_gateway_chat_session("telegram", chat_key)
            .expect("mapping should clear");

        assert_eq!(
            store
                .load_gateway_chat_session("telegram", chat_key)
                .expect("cleared mapping should load"),
            None
        );
    }

    let _ = std::fs::remove_file(path);
}

#[test]
fn gateway_chat_model_mapping_round_trip() {
    let path = std::env::temp_dir().join(format!(
        "tidev-session-store-gateway-model-{}.sqlite3",
        uuid::Uuid::new_v4()
    ));

    {
        let store = SessionStore::open(&path).expect("store should open");
        let chat_key = "12345";

        store
            .set_gateway_chat_model("telegram", chat_key, "openai", "gpt-4o-mini")
            .expect("model mapping should save");

        assert_eq!(
            store
                .load_gateway_chat_model("telegram", chat_key)
                .expect("model mapping should load"),
            Some(("openai".to_string(), "gpt-4o-mini".to_string()))
        );

        store
            .set_gateway_chat_model("telegram", chat_key, "deepseek", "deepseek-v4-flash")
            .expect("model mapping should update");

        assert_eq!(
            store
                .load_gateway_chat_model("telegram", chat_key)
                .expect("updated model mapping should load"),
            Some(("deepseek".to_string(), "deepseek-v4-flash".to_string()))
        );

        store
            .clear_gateway_chat_model("telegram", chat_key)
            .expect("model mapping should clear");

        assert_eq!(
            store
                .load_gateway_chat_model("telegram", chat_key)
                .expect("cleared model mapping should load"),
            None
        );
    }

    let _ = std::fs::remove_file(path);
}
