use crate::errors::*;
use std::path::PathBuf;
use structopt::StructOpt;
use std::str::FromStr;

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum Source {
    local,
    flickr,
    icloud,
}

#[allow(non_camel_case_types)]
#[derive(Debug, Clone, PartialEq)]
pub(crate) enum Operation {
    initialize,
    update,
    clean,
}

#[derive(StructOpt, Debug, Clone)]
#[structopt(name = "PhotoBook", about = "Thanks using PhotoBook CLI, please use -h or --help for more")]
pub(crate) enum Cli {
    /// PhotoBook harvests a filesystem or cloud, and stores information about files in ElasticSearch
    Harvest {
        /// Declare the source
        #[structopt(short, long, parse(try_from_str))]
        source: Source,
        /// Select the operation to process
        #[structopt(short, long, default_value = "update", parse(try_from_str))]
        operation: Operation,
        /// Precise the path to harvest, only needed if you run a filesystem harvesting
        #[structopt(short, long, required_if("source", "local"), parse(from_os_str))]
        path: Option<PathBuf>,
    },
    /// Sort, order and organize your photos by year, month and day
    Organize {
        /// Define the source path
        #[structopt(short, long, parse(from_os_str))]
        from: PathBuf,
        /// Declare the target path
        #[structopt(short, long, parse(from_os_str))]
        to: PathBuf,
    },
    /// Backup photos from cloud storage to local disk
    Download {
        /// Choose the cloud source
        #[structopt(short = "f", long, default_value = "flickr", parse(try_from_str))]
        source: Source,
        /// Declare the local target path
        #[structopt(short, long, parse(from_os_str))]
        to: PathBuf,
        /// Precise optionally a specific server
        #[structopt(short, long)]
        server: Option<String>,
    },
    /// Duplicate the local photo store to another disk
    Backup {
        /// Select the source path
        #[structopt(short, long, parse(from_os_str))]
        from: PathBuf,
        /// Declare the local target path
        #[structopt(short, long, parse(from_os_str))]
        to: PathBuf,
    },
}

impl FromStr for Source {
    type Err = Error;
    fn from_str(source: &str) -> Result<Source> {
        match source.to_lowercase().as_str() {
            "local" => Ok(Source::local),
            "flickr" => Ok(Source::flickr),
            "icloud" => Ok(Source::icloud),
            _ => bail!("please select a valid source (local, flickr or icloud)")
        }
    }
}

impl FromStr for Operation {
    type Err = Error;
    fn from_str(operation: &str) -> Result<Operation> {
        match operation.to_lowercase().as_str() {
            "initialize" => Ok(Operation::initialize),
            "update" => Ok(Operation::update),
            "clean" => Ok(Operation::clean),
            _ => bail!("please select a valid operation (initialize, update or clean)")
        }
    }
}

