// Generated by Qleany. Edit at your own risk! Be careful when regenerating this file
// as changes will be lost.
use super::common::strip_generated_by_lines;
use crate::GetDiffDto;
use crate::GetDiffReturnDto;
use anyhow::{Result, anyhow};
use common::database::QueryUnitOfWork;
use common::entities::{File, Root, Workspace};
use common::types::EntityId;
use std::path::PathBuf;

pub trait GetFileDiffUnitOfWorkFactoryTrait {
    fn create(&self) -> Box<dyn GetFileDiffUnitOfWorkTrait>;
}
#[macros::uow_action(entity = "Root", action = "GetAllRO")]
#[macros::uow_action(entity = "Root", action = "GetRelationshipRO")]
#[macros::uow_action(entity = "Workspace", action = "GetRO")]
#[macros::uow_action(entity = "File", action = "GetRO")]
pub trait GetFileDiffUnitOfWorkTrait: QueryUnitOfWork {}

pub struct GetFileDiffUseCase {
    uow_factory: Box<dyn GetFileDiffUnitOfWorkFactoryTrait>,
}

impl GetFileDiffUseCase {
    pub fn new(uow_factory: Box<dyn GetFileDiffUnitOfWorkFactoryTrait>) -> Self {
        GetFileDiffUseCase { uow_factory }
    }

    pub fn execute(&mut self, dto: &GetDiffDto) -> Result<GetDiffReturnDto> {
        let uow = self.uow_factory.create();
        uow.begin_transaction()?;

        // Get the file entity
        let file: File = uow
            .get_file(&dto.file_id)?
            .ok_or_else(|| anyhow!("File entity not found for id {}", dto.file_id))?;

        let generated_code = file
            .generated_code
            .as_deref()
            .ok_or_else(|| anyhow!("File has no generated code"))?;

        // Get root -> workspace for manifest path
        let roots = uow.get_all_root()?;
        let root = roots
            .into_iter()
            .next()
            .ok_or_else(|| anyhow!("Root entity not found"))?;

        let workspace_ids = uow.get_root_relationship(
            &root.id,
            &common::direct_access::root::RootRelationshipField::Workspace,
        )?;
        let workspace_id = workspace_ids
            .first()
            .cloned()
            .ok_or_else(|| anyhow!("No workspace found"))?;
        let workspace: Workspace = uow
            .get_workspace(&workspace_id)?
            .ok_or_else(|| anyhow!("Workspace entity not found"))?;
        let root_path = PathBuf::from(&workspace.manifest_absolute_path);

        uow.end_transaction()?;

        // Build disk path
        let mut disk_path = root_path;
        if !file.relative_path.is_empty() {
            disk_path = disk_path.join(&file.relative_path);
        }
        disk_path = disk_path.join(&file.name);

        // Read disk content (empty string if file doesn't exist yet)
        let disk_content = std::fs::read_to_string(&disk_path).unwrap_or_default();

        // Strip "Generated by Qleany" lines from both sides
        let stripped_disk = strip_generated_by_lines(&disk_content);
        let stripped_generated = strip_generated_by_lines(generated_code);

        // Compute unified diff
        let diff = similar::TextDiff::from_lines(&stripped_disk, &stripped_generated);
        let diff_text = diff
            .unified_diff()
            .context_radius(3)
            .header(&disk_path.display().to_string(), "generated")
            .to_string();

        Ok(GetDiffReturnDto { diff_text })
    }
}
