use std::path::PathBuf;

use async_trait::async_trait;

use crate::cli::{Operation, Source};
use crate::harvest::filesystem_harvester::FileSystemHarvester;
use crate::harvest::flickr_harvester::FlickrHarvester;
use crate::harvest::harvester::Harvester;
use crate::processors::processor::Processor;
use crate::processors::report::Report;

#[derive(Debug, Clone)]
pub(crate) struct HarvestProcessor {
    source: Source,
    operation: Operation,
    path: Option<PathBuf>,
}

impl HarvestProcessor {
    pub fn new(source: Source, operation: Operation, path: Option<PathBuf>) -> Self {
        HarvestProcessor {
            source,
            operation,
            path,
        }
    }

    //noinspection DuplicatedCode
    async fn execute_local_harvest(&self) -> Result<Report, Vec<String>> {
        if self.path.is_none() {
            return Err(vec![String::from("missing path argument")])
        }

        let harvester = FileSystemHarvester::new(self.path.as_ref().unwrap().clone()
            .into_os_string().into_string().unwrap_or_default());
        match self.operation {
            Operation::initialize => match harvester.initialize_db().await {
                Ok(n) => Ok(n),
                Err(n) => Err(n)
            },
            Operation::update => match harvester.update_db().await {
                Ok(n) => Ok(n),
                Err(n) => Err(n)
            },
            Operation::clean => match harvester.clean_db().await {
                Ok(n) => Ok(n),
                Err(n) => Err(n)
            },
        }
    }

    //noinspection DuplicatedCode
    async fn execute_flickr_harvest(&self) -> Result<Report, Vec<String>> {
        let harvester = FlickrHarvester::new();
        match self.operation {
            Operation::initialize => match harvester.initialize_db().await {
                Ok(n) => Ok(n),
                Err(n) => Err(n)
            },
            Operation::update => match harvester.update_db().await {
                Ok(n) => Ok(n),
                Err(n) => Err(n)
            },
            Operation::clean => match harvester.clean_db().await {
                Ok(n) => Ok(n),
                Err(n) => Err(n)
            },
        }
    }
}

#[async_trait]
impl Processor for HarvestProcessor {
    async fn process(&self) -> Result<Report, Vec<String>> {
        if self.source.eq(&Source::local) {
            self.execute_local_harvest().await
        } else if self.source.eq(&Source::flickr) {
            self.execute_flickr_harvest().await
        } else {
            Err(vec![String::from("error during process")])
        }
    }
}
