use rusqlite::Connection;
use tracing::debug;

use crate::core::error::Result;
use crate::gitlab::types::GitLabMrDiff;

/// Derive the change type from GitLab's boolean flags.
fn derive_change_type(diff: &GitLabMrDiff) -> &'static str {
    if diff.new_file {
        "added"
    } else if diff.renamed_file {
        "renamed"
    } else if diff.deleted_file {
        "deleted"
    } else {
        "modified"
    }
}

/// Replace all file change records for a given MR with the provided diffs.
/// Uses DELETE+INSERT (simpler than UPSERT for array replacement).
///
/// Does NOT manage its own transaction — the caller is responsible for
/// wrapping this in a transaction when atomicity with other operations
/// (job completion, watermark update) is needed.
pub fn upsert_mr_file_changes(
    conn: &Connection,
    mr_local_id: i64,
    project_id: i64,
    diffs: &[GitLabMrDiff],
) -> Result<usize> {
    conn.execute(
        "DELETE FROM mr_file_changes WHERE merge_request_id = ?1",
        [mr_local_id],
    )?;

    let mut stmt = conn.prepare_cached(
        "INSERT INTO mr_file_changes (merge_request_id, project_id, old_path, new_path, change_type) \
         VALUES (?1, ?2, ?3, ?4, ?5)",
    )?;

    let mut inserted = 0;
    for diff in diffs {
        let old_path = if diff.renamed_file {
            Some(diff.old_path.as_str())
        } else {
            None
        };
        let change_type = derive_change_type(diff);

        stmt.execute(rusqlite::params![
            mr_local_id,
            project_id,
            old_path,
            diff.new_path,
            change_type,
        ])?;
        inserted += 1;
    }

    if inserted > 0 {
        debug!(inserted, mr_local_id, "Stored MR file changes");
    }

    Ok(inserted)
}

#[cfg(test)]
#[path = "mr_diffs_tests.rs"]
mod tests;
