use std::path::PathBuf;
use thiserror::Error;

#[derive(Error, Debug)]
#[allow(dead_code)]
pub enum DbtLineageError {
    #[error("dbt project not found: no dbt_project.yml in {0}")]
    ProjectNotFound(PathBuf),

    #[error("failed to read file {path}: {source}")]
    FileReadError {
        path: PathBuf,
        source: std::io::Error,
    },

    #[error("failed to parse YAML in {path}: {source}")]
    YamlParseError {
        path: PathBuf,
        source: serde_saphyr::Error,
    },

    #[error("model not found: {0}")]
    ModelNotFound(String),

    #[error("cycle detected in lineage graph")]
    CycleDetected,

    #[error("duplicate model name '{name}' found in {path1} and {path2}")]
    DuplicateModel {
        name: String,
        path1: PathBuf,
        path2: PathBuf,
    },

    #[error("failed to parse artifact {path}: {source}")]
    ArtifactParseError {
        path: PathBuf,
        source: serde_json::Error,
    },
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::io;

    #[test]
    fn test_error_display() {
        let err = DbtLineageError::ProjectNotFound(PathBuf::from("/foo"));
        assert_eq!(
            err.to_string(),
            "dbt project not found: no dbt_project.yml in /foo"
        );

        let io_err = io::Error::new(io::ErrorKind::NotFound, "file not found");
        let err = DbtLineageError::FileReadError {
            path: PathBuf::from("/bar.sql"),
            source: io_err,
        };
        assert!(err.to_string().contains("/bar.sql"));

        let err = DbtLineageError::ModelNotFound("orders".into());
        assert_eq!(err.to_string(), "model not found: orders");

        let err = DbtLineageError::CycleDetected;
        assert_eq!(err.to_string(), "cycle detected in lineage graph");

        let err = DbtLineageError::DuplicateModel {
            name: "orders".into(),
            path1: PathBuf::from("a.sql"),
            path2: PathBuf::from("b.sql"),
        };
        assert!(err.to_string().contains("duplicate model name"));
        assert!(err.to_string().contains("orders"));
    }
}
