use std::{io::Error, path::PathBuf};

use log::SetLoggerError;
use log4rs::config::runtime::ConfigErrors;

use crate::io::OutputFormat;


#[derive(Debug, thiserror::Error)]
pub enum PathError {
    #[error("Provided path '{0}' is not a file")]
    IsNotFile(PathBuf),
    #[error("Provided path '{0}' does not exist")]
    DoesNotExist(PathBuf),
    #[error("Extension could not be extracted from path '{0}'")]
    ExtensionNone(PathBuf),
    #[error("Provided path '{0}' has an invalid extension")]
    InvalidExtension(String),
    #[error("Unexpected format {0} (must be one of {1:?}")]
    UnexpectedFormat(String, Vec<OutputFormat>),
    #[error("Provided path '{0}' is a directory")]
    IsDir(PathBuf),
    #[error("Failed to create directory '{0}'")]
    FailedToCreateDir(PathBuf),
    #[error("Base directory does not exist for '{0}'")]
    BaseDirNotExist(PathBuf),
    #[error("File '{0}' already exists and force overwrite is disabled")]
    FileExists(PathBuf),
    #[error("Io error: {0}")]
    IoError(#[from] std::io::Error)
}


#[derive(Debug, thiserror::Error)]
pub enum Pod5PathError {
    #[error("IoError: {0}")]
    IoError(#[from] Error),
    #[error("No valid pod5 files found")]
    NoValidFilesFound,   
}


#[derive(Debug, thiserror::Error)]
pub enum CliError {
    #[error("Invalid argument for '{0}'")]
    ArgumentNone(String),
    #[error("PathError: {0}")]
    PathError(#[from] PathError),
    #[error("Pod5PathError: {0}")]
    Pod5PathError(#[from] Pod5PathError),
    #[error("Invalid value for argument {0}: {1}")]
    InvalidArgument(String, String),
    #[error("Io error: {0}")]
    IoError(#[from] std::io::Error),
    #[error("Nested output is only available for parquet output.")]
    InvalidOutputShape
}

#[derive(Debug, thiserror::Error)]
pub enum LoggerError {
    #[error("IO error: {0}")]
    IoError(#[from] std::io::Error),
    #[error("Log error: {0}")]
    LogError(#[from] SetLoggerError),
    #[error("Log4rs error: {0}")]
    ConfigError(#[from] ConfigErrors)
}

#[derive(Debug, thiserror::Error)]
pub enum InterpolationError {
    #[error("X and Y references must have the same length (X: {0} vs Y: {1})")]
    DifferentLength(usize, usize),
    #[error("Reference vectors must not be empty")]
    EmptyReference,
    #[error("Reference vectors must be sorted")]
    ReferenceUnsorted
}

#[derive(Debug, thiserror::Error)]
pub enum LinspaceError {
    #[error("The num argument must be larger than 0")]
    ZeroElements
}