// 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 anyhow::{Result, anyhow};
use common::database::CommandUnitOfWork;
use common::entities::{File, FileStatus, Root, System, Workspace};
use common::types::EntityId;
use std::path::PathBuf;

pub trait FillStatusInFilesUnitOfWorkFactoryTrait {
    fn create(&self) -> Box<dyn FillStatusInFilesUnitOfWorkTrait>;
}
#[macros::uow_action(entity = "Root", action = "GetAll")]
#[macros::uow_action(entity = "Root", action = "GetRelationship")]
#[macros::uow_action(entity = "Workspace", action = "Get")]
#[macros::uow_action(entity = "System", action = "Get")]
#[macros::uow_action(entity = "System", action = "GetRelationship")]
#[macros::uow_action(entity = "File", action = "GetMulti")]
#[macros::uow_action(entity = "File", action = "UpdateMulti")]
pub trait FillStatusInFilesUnitOfWorkTrait: CommandUnitOfWork {}

pub struct FillStatusInFilesUseCase {
    uow_factory: Box<dyn FillStatusInFilesUnitOfWorkFactoryTrait>,
}

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

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

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

        // Get workspace for manifest_absolute_path (= root path on disk)
        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);

        // Get system and its file IDs
        let system_ids = uow.get_root_relationship(
            &root.id,
            &common::direct_access::root::RootRelationshipField::System,
        )?;
        let system_id = system_ids
            .first()
            .cloned()
            .ok_or_else(|| anyhow!("No system found"))?;
        let file_ids = uow.get_system_relationship(
            &system_id,
            &common::direct_access::system::SystemRelationshipField::Files,
        )?;

        if file_ids.is_empty() {
            uow.commit()?;
            return Ok(());
        }

        // Load all file entities
        let files: Vec<File> = uow
            .get_file_multi(&file_ids)?
            .into_iter()
            .flatten()
            .collect();

        // Compare each file's generated_code with the actual file on disk
        let mut files_to_update: Vec<File> = Vec::new();
        for file in &files {
            let Some(ref generated_code) = file.generated_code else {
                // No generated code yet — skip (status stays Unknown)
                continue;
            };

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

            let new_status = match std::fs::read_to_string(&disk_path) {
                Ok(disk_content) => {
                    if strip_generated_by_lines(&disk_content)
                        == strip_generated_by_lines(generated_code)
                    {
                        FileStatus::Unchanged
                    } else {
                        FileStatus::Modified
                    }
                }
                Err(_) => FileStatus::New,
            };

            if file.status != new_status {
                let mut updated = file.clone();
                updated.status = new_status;
                updated.updated_at = chrono::Utc::now();
                files_to_update.push(updated);
            }
        }

        if !files_to_update.is_empty() {
            uow.update_file_multi(&files_to_update)?;
        }

        uow.commit()?;
        Ok(())
    }
}
