use serde::Serialize;
use std::path::PathBuf;

#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum EntryStatus {
    Identical,
    Modified,
    LeftOnly,
    RightOnly,
    /// One side has a file, the other has a directory with the same name.
    /// `left_is_dir` indicates whether the left side is the directory.
    TypeMismatch {
        left_is_dir: bool,
    },
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase", tag = "type")]
pub enum TreeEntry {
    #[serde(rename_all = "camelCase")]
    File { name: String, status: EntryStatus },
    #[serde(rename_all = "camelCase")]
    Dir {
        name: String,
        status: EntryStatus,
        children: Vec<TreeEntry>,
    },
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DirTree {
    pub name: String,
    pub entries: Vec<TreeEntry>,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CompareResult {
    pub left_root: PathBuf,
    pub right_root: PathBuf,
    pub tree: DirTree,
    pub total_files: usize,
    pub modified_files: usize,
    pub left_only_files: usize,
    pub right_only_files: usize,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase", tag = "type")]
pub enum DiffChunk {
    #[serde(rename_all = "camelCase")]
    Equal {
        lines: Vec<String>,
        left_start: usize,
        right_start: usize,
    },
    #[serde(rename_all = "camelCase")]
    Insert {
        lines: Vec<String>,
        right_start: usize,
    },
    #[serde(rename_all = "camelCase")]
    Delete {
        lines: Vec<String>,
        left_start: usize,
    },
    #[serde(rename_all = "camelCase")]
    Replace {
        left_lines: Vec<String>,
        right_lines: Vec<String>,
        left_start: usize,
        right_start: usize,
    },
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FileDiff {
    pub left_path: PathBuf,
    pub right_path: PathBuf,
    pub chunks: Vec<DiffChunk>,
}
