use std::path::PathBuf;
use std::sync::Arc;

use domain::{
    AssistantContextProvider, FileSystem, Issue, IssueActor, IssueId, IssueNumber, IssuePriority,
    IssueStatus, MarkdownDoc, Project, ProjectId, ProjectPath,
};
use infrastructure::{FsAssistantContextStore, LocalFileSystem};
use uuid::Uuid;

struct TempDir(PathBuf);

impl TempDir {
    fn new() -> Self {
        let path = std::env::temp_dir().join(format!("idea-assistant-context-{}", Uuid::new_v4()));
        std::fs::create_dir_all(&path).unwrap();
        Self(path)
    }

    fn app_data_dir(&self) -> String {
        self.0.join("app-data").to_string_lossy().into_owned()
    }

    fn project_root(&self) -> ProjectPath {
        ProjectPath::new(self.0.join("project").to_string_lossy().into_owned()).unwrap()
    }
}

impl Drop for TempDir {
    fn drop(&mut self) {
        let _ = std::fs::remove_dir_all(&self.0);
    }
}

fn project(root: ProjectPath) -> Project {
    Project::new(
        ProjectId::from_uuid(Uuid::from_u128(1)),
        "demo",
        root,
        domain::remote::RemoteRef::local(),
        1_000,
    )
    .unwrap()
}

fn issue(number: u64) -> Issue {
    Issue::new(
        IssueId::from_uuid(Uuid::from_u128(number as u128)),
        IssueNumber::new(number).unwrap(),
        "Clarify onboarding",
        MarkdownDoc::new("Initial description body"),
        IssueStatus::Open,
        IssuePriority::High,
        MarkdownDoc::new("Carnet notes"),
        Vec::new(),
        Vec::new(),
        IssueActor::User,
        1_000,
    )
    .unwrap()
}

fn store(app_data_dir: String) -> FsAssistantContextStore {
    let fs: Arc<dyn FileSystem> = Arc::new(LocalFileSystem::new());
    FsAssistantContextStore::new(fs, app_data_dir)
}

#[tokio::test]
async fn default_context_is_embedded_and_injects_the_ticket() {
    let tmp = TempDir::new();
    let project = project(tmp.project_root());
    let store = store(tmp.app_data_dir());

    let ctx = store
        .prepare_ticket_assistant_context(&project, &issue(7))
        .await
        .unwrap();

    let body = ctx.content.as_str();
    assert!(body.contains("# Ticket Assistant"));
    assert!(body.contains("- Ref: #7"));
    assert!(body.contains("- Title: Clarify onboarding"));
    assert!(body.contains("Initial description body"));
    assert!(body.contains("Carnet notes"));
    assert_eq!(ctx.project_root, project.root.as_str());
    assert_eq!(ctx.relative_path, "ticket-assistant.md");
}

#[tokio::test]
async fn app_data_override_replaces_the_embedded_default() {
    let tmp = TempDir::new();
    let app_data_dir = tmp.app_data_dir();
    let override_path = PathBuf::from(&app_data_dir)
        .join("assistant")
        .join("ticket-assistant.md");
    std::fs::create_dir_all(override_path.parent().unwrap()).unwrap();
    std::fs::write(&override_path, "# Custom assistant").unwrap();

    let project = project(tmp.project_root());
    let store = store(app_data_dir);
    let ctx = store
        .prepare_ticket_assistant_context(&project, &issue(8))
        .await
        .unwrap();

    let body = ctx.content.as_str();
    assert!(body.starts_with("# Custom assistant"));
    assert!(!body.contains("You are IdeA's ticket editing assistant"));
    assert!(body.contains("- Ref: #8"));
}
