use serde::{Deserialize, Serialize};

use crate::cmd::oid::ObjectId;

pub mod diff_index_to_tree;
pub mod diff_patch;
pub mod diff_stats;
pub mod diff_tree_to_tree;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum DiffDeltaStatus {
    Unmodified,
    Added,
    Deleted,
    Modified,
    Renamed,
    Copied,
    Typechange,
    Conflicted,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiffFile {
    pub oid: Option<ObjectId>,
    pub path: Option<String>,
    pub size: u64,
    pub is_binary: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiffHunk {
    pub old_start: u32,
    pub old_lines: u32,
    pub new_start: u32,
    pub new_lines: u32,
    pub header: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiffDelta {
    pub status: DiffDeltaStatus,
    pub old_file: DiffFile,
    pub new_file: DiffFile,
    pub nfiles: u16,
    pub hunks: Vec<DiffHunk>,
    pub lines: Vec<DiffLine>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiffLine {
    pub content: String,
    pub origin: char,
    pub old_lineno: Option<u32>,
    pub new_lineno: Option<u32>,
    pub num_lines: u32,
    pub content_offset: i64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiffStats {
    pub files_changed: usize,
    pub insertions: usize,
    pub deletions: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DiffResult {
    pub stats: DiffStats,
    pub deltas: Vec<DiffDelta>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SideBySideChangeType {
    Unchanged,
    Added,
    Removed,
    Modified,
    Empty,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SideBySideLine {
    pub left_line_no: Option<u32>,
    pub right_line_no: Option<u32>,
    pub left_content: String,
    pub right_content: String,
    pub change_type: SideBySideChangeType,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SideBySideFile {
    pub path: String,
    pub additions: usize,
    pub deletions: usize,
    pub is_binary: bool,
    pub is_rename: bool,
    pub lines: Vec<SideBySideLine>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SideBySideDiffResult {
    pub files: Vec<SideBySideFile>,
    pub total_additions: usize,
    pub total_deletions: usize,
}

#[derive(Debug, Clone, Default)]
pub struct DiffOptions {
    pub context_lines: u32,
    pub pathspec: Vec<String>,
    pub ignore_whitespace: bool,
    pub force_text: bool,
    pub reverse: bool,
}
