use std::path::PathBuf;

use app_tauri_lib::state::AppState;
use application::CreateProjectInput;
use infrastructure::TicketToolProvider;
use serde_json::json;
use uuid::Uuid;

fn temp_path(tag: &str) -> PathBuf {
    std::env::temp_dir().join(format!("idea-app-tauri-test-{tag}-{}", Uuid::new_v4()))
}

#[tokio::test]
async fn idea_ticket_read_is_best_effort_but_read_carnet_stays_strict_when_carnet_file_is_missing()
{
    let state = AppState::build(temp_path("appdata"));
    let project_root = temp_path("project").to_string_lossy().into_owned();
    let project = state
        .create_project
        .execute(CreateProjectInput {
            name: "App Tauri Tickets".to_owned(),
            root: project_root,
            remote: None,
            default_profile_id: None,
        })
        .await
        .expect("test project is created")
        .project;

    let created = state
        .ticket_tool_binder
        .handle_ticket_tool(
            &project,
            "qa-agent",
            "idea_ticket_create",
            json!({
                "title": "Missing carnet fallback",
                "description": "Created by app-tauri integration test",
                "priority": "high",
                "status": "open"
            }),
        )
        .await
        .expect("ticket create succeeds");
    let ticket_ref = created["ref"]
        .as_str()
        .expect("ticket ref is present")
        .to_owned();

    let read = state
        .ticket_tool_binder
        .handle_ticket_tool(
            &project,
            "qa-agent",
            "idea_ticket_read",
            json!({ "ref": ticket_ref, "includeCarnet": true }),
        )
        .await
        .expect("ticket read succeeds");
    assert!(
        read["carnet"].is_string(),
        "ticket read returns a string carnet"
    );

    std::fs::remove_file(
        PathBuf::from(project.root.as_str())
            .join(".ideai")
            .join("tickets")
            .join(ticket_ref.trim_start_matches('#'))
            .join("carnet.md"),
    )
    .expect("test removes ticket carnet");

    let read_without_carnet_file = state
        .ticket_tool_binder
        .handle_ticket_tool(
            &project,
            "qa-agent",
            "idea_ticket_read",
            json!({ "ref": ticket_ref, "includeCarnet": true }),
        )
        .await
        .expect("ticket read stays best-effort");
    assert_eq!(read_without_carnet_file["ref"], ticket_ref);
    assert_eq!(read_without_carnet_file["carnet"], "");

    let strict_err = state
        .ticket_tool_binder
        .handle_ticket_tool(
            &project,
            "qa-agent",
            "idea_ticket_read_carnet",
            json!({ "ref": ticket_ref }),
        )
        .await
        .expect_err("strict carnet read must fail when carnet.md is missing");
    assert_eq!(strict_err.code, "notFound");
}

#[tokio::test]
async fn idea_ticket_bulk_delete_deletes_each_ref_and_reports_partial_errors() {
    let state = AppState::build(temp_path("appdata"));
    let project_root = temp_path("project").to_string_lossy().into_owned();
    let project = state
        .create_project
        .execute(CreateProjectInput {
            name: "App Tauri Bulk Delete".to_owned(),
            root: project_root,
            remote: None,
            default_profile_id: None,
        })
        .await
        .expect("test project is created")
        .project;

    let first = state
        .ticket_tool_binder
        .handle_ticket_tool(
            &project,
            "qa-agent",
            "idea_ticket_create",
            json!({ "title": "Bulk delete A" }),
        )
        .await
        .expect("first ticket create succeeds");
    let second = state
        .ticket_tool_binder
        .handle_ticket_tool(
            &project,
            "qa-agent",
            "idea_ticket_create",
            json!({ "title": "Bulk delete B" }),
        )
        .await
        .expect("second ticket create succeeds");
    let first_ref = first["ref"].as_str().expect("first ref").to_owned();
    let second_ref = second["ref"].as_str().expect("second ref").to_owned();

    let out = state
        .ticket_tool_binder
        .handle_ticket_tool(
            &project,
            "qa-agent",
            "idea_ticket_bulk_delete",
            json!({ "refs": [first_ref.clone(), "#999", second_ref.clone()] }),
        )
        .await
        .expect("bulk delete dispatch succeeds");

    let items = out["items"].as_array().expect("bulk items");
    assert_eq!(items.len(), 3);
    assert_eq!(items[0]["ref"], first_ref);
    assert_eq!(items[0]["ok"], true);
    assert_eq!(items[1]["ref"], "#999");
    assert_eq!(items[1]["ok"], false);
    assert_eq!(items[1]["error"]["code"], "NOT_FOUND");
    assert_eq!(items[2]["ref"], second_ref);
    assert_eq!(items[2]["ok"], true);

    for deleted_ref in [first_ref, second_ref] {
        let err = state
            .ticket_tool_binder
            .handle_ticket_tool(
                &project,
                "qa-agent",
                "idea_ticket_read",
                json!({ "ref": deleted_ref }),
            )
            .await
            .expect_err("deleted ticket read must fail");
        assert_eq!(err.code, "notFound");
    }
}
