use super::*;

#[test]
fn tracks_workspace_folder_changes() {
    let workspace_root = std::env::temp_dir().join(format!(
        "omena-lsp-server-added-workspace-{}",
        std::process::id()
    ));
    let src_dir = workspace_root.join("src");
    let style_path = src_dir.join("Added.module.scss");
    let _ = std::fs::remove_dir_all(&workspace_root);
    let create_dir_result = std::fs::create_dir_all(&src_dir);
    assert!(
        create_dir_result.is_ok(),
        "create added-workspace fixture directory: {:?}",
        create_dir_result.err(),
    );
    let write_result = std::fs::write(&style_path, ".added { color: red; }");
    assert!(
        write_result.is_ok(),
        "write added-workspace style fixture: {:?}",
        write_result.err(),
    );
    let workspace_uri = format!("file://{}", workspace_root.display());
    let style_uri = format!("file://{}", style_path.display());
    let mut state = LspShellState::default();
    handle_lsp_message(
        &mut state,
        json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": "initialize",
            "params": {
                "workspaceFolders": [
                    {
                        "uri": "file:///workspace-a",
                        "name": "workspace-a",
                    },
                ],
            },
        }),
    );
    handle_lsp_message(
        &mut state,
        json!({
            "jsonrpc": "2.0",
            "method": "workspace/didChangeWorkspaceFolders",
            "params": {
                "event": {
                    "removed": [
                        {
                            "uri": "file:///workspace-a",
                            "name": "workspace-a",
                        },
                    ],
                    "added": [
                        {
                            "uri": workspace_uri,
                            "name": "workspace-b",
                        },
                    ],
                },
            },
        }),
    );

    assert_eq!(state.workspace_folder_count(), 1);
    assert!(state.workspace_folder("file:///workspace-a").is_none());
    assert!(state.workspace_folder(workspace_uri.as_str()).is_some());
    let indexed = state
        .document(style_uri.as_str())
        .and_then(|document| document.style_summary.as_ref());
    assert_eq!(
        indexed.map(|summary| summary.selector_names.clone()),
        Some(vec!["added".to_string()]),
    );
    handle_lsp_message(
        &mut state,
        json!({
            "jsonrpc": "2.0",
            "method": "workspace/didChangeWorkspaceFolders",
            "params": {
                "event": {
                    "removed": [
                        {
                            "uri": workspace_uri,
                            "name": "workspace-b",
                        },
                    ],
                    "added": [],
                },
            },
        }),
    );
    assert!(state.workspace_folder(workspace_uri.as_str()).is_none());
    assert!(state.document(style_uri.as_str()).is_none());
    let _ = std::fs::remove_dir_all(&workspace_root);
}

#[test]
fn retargets_indexed_style_documents_after_nested_workspace_removal() {
    let workspace_root = std::env::temp_dir().join(format!(
        "omena-lsp-server-nested-workspace-retarget-{}",
        std::process::id()
    ));
    let nested_root = workspace_root.join("packages").join("app");
    let src_dir = nested_root.join("src");
    let style_path = src_dir.join("Nested.module.scss");
    let _ = std::fs::remove_dir_all(&workspace_root);
    let create_dir_result = std::fs::create_dir_all(&src_dir);
    assert!(
        create_dir_result.is_ok(),
        "create nested-workspace fixture directory: {:?}",
        create_dir_result.err(),
    );
    let write_result = std::fs::write(&style_path, ".nested { color: red; }");
    assert!(
        write_result.is_ok(),
        "write nested-workspace style fixture: {:?}",
        write_result.err(),
    );

    let workspace_uri = format!("file://{}", workspace_root.display());
    let nested_workspace_uri = format!("file://{}", nested_root.display());
    let style_uri = format!("file://{}", style_path.display());
    let mut state = LspShellState::default();
    handle_lsp_message(
        &mut state,
        json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": "initialize",
            "params": {
                "workspaceFolders": [
                    {
                        "uri": workspace_uri,
                        "name": "workspace",
                    },
                    {
                        "uri": nested_workspace_uri,
                        "name": "app",
                    },
                ],
            },
        }),
    );
    handle_lsp_message(
        &mut state,
        json!({
            "jsonrpc": "2.0",
            "method": "initialized",
            "params": {},
        }),
    );

    let indexed = state.document(style_uri.as_str());
    assert_eq!(
        indexed.and_then(|document| document.workspace_folder_uri.as_deref()),
        Some(nested_workspace_uri.as_str()),
    );
    assert_eq!(
        indexed
            .and_then(|document| document.style_summary.as_ref())
            .map(|summary| summary.selector_names.clone()),
        Some(vec!["nested".to_string()]),
    );

    handle_lsp_message(
        &mut state,
        json!({
            "jsonrpc": "2.0",
            "method": "workspace/didChangeWorkspaceFolders",
            "params": {
                "event": {
                    "removed": [
                        {
                            "uri": nested_workspace_uri,
                            "name": "app",
                        },
                    ],
                    "added": [],
                },
            },
        }),
    );

    let retargeted = state.document(style_uri.as_str());
    assert_eq!(
        retargeted.and_then(|document| document.workspace_folder_uri.as_deref()),
        Some(workspace_uri.as_str()),
    );
    assert_eq!(
        retargeted
            .and_then(|document| document.style_summary.as_ref())
            .map(|summary| summary.selector_names.clone()),
        Some(vec!["nested".to_string()]),
    );

    handle_lsp_message(
        &mut state,
        json!({
            "jsonrpc": "2.0",
            "method": "workspace/didChangeWorkspaceFolders",
            "params": {
                "event": {
                    "removed": [
                        {
                            "uri": workspace_uri,
                            "name": "workspace",
                        },
                    ],
                    "added": [],
                },
            },
        }),
    );
    assert!(state.document(style_uri.as_str()).is_none());
    let _ = std::fs::remove_dir_all(&workspace_root);
}

#[test]
fn assigns_document_workspace_folder_by_longest_uri_prefix() {
    let mut state = LspShellState::default();
    handle_lsp_message(
        &mut state,
        json!({
            "jsonrpc": "2.0",
            "id": 1,
            "method": "initialize",
            "params": {
                "workspaceFolders": [
                    {
                        "uri": "file:///workspace",
                        "name": "workspace",
                    },
                    {
                        "uri": "file:///workspace/packages/app",
                        "name": "app",
                    },
                ],
            },
        }),
    );

    handle_lsp_message(
        &mut state,
        json!({
            "jsonrpc": "2.0",
            "method": "textDocument/didOpen",
            "params": {
                "textDocument": {
                    "uri": "file:///workspace/packages/app/src/App.tsx",
                    "languageId": "typescriptreact",
                    "version": 1,
                    "text": "export const App = () => null;",
                },
            },
        }),
    );

    assert_eq!(
        state
            .document("file:///workspace/packages/app/src/App.tsx")
            .and_then(|document| document.workspace_folder_uri.as_deref()),
        Some("file:///workspace/packages/app"),
    );

    handle_lsp_message(
        &mut state,
        json!({
            "jsonrpc": "2.0",
            "method": "workspace/didChangeWorkspaceFolders",
            "params": {
                "event": {
                    "removed": [
                        {
                            "uri": "file:///workspace/packages/app",
                            "name": "app",
                        },
                    ],
                    "added": [],
                },
            },
        }),
    );

    assert_eq!(
        state
            .document("file:///workspace/packages/app/src/App.tsx")
            .and_then(|document| document.workspace_folder_uri.as_deref()),
        Some("file:///workspace"),
    );
}
