use vfile::transport::streaming::streaming_transport::StreamingTransport;

use crate::chopper::error::Result;
use crate::input::defaults::{create_default_dir_transports, create_default_source_factories};
use crate::input::dir::source::SourceDirInputFactory;
use crate::input::factory::{ChopperInputFactory, InputFactory};
use crate::input::location::factory::LocationInputFactory;
use crate::source::csv_input_config::CSVInputConfig;
use crate::source::source_factory::ChopperSourceFactory;
use crate::util::dc_factory::DCFactory;

pub struct ChopperInputFactoryBuilder {
    dc_factory: Option<DCFactory>,
    csv_input_config: Option<CSVInputConfig>,
    user_source_factories: Option<Vec<Box<ChopperSourceFactory>>>,
    user_streaming_transports: Option<Vec<Box<dyn StreamingTransport>>>,
}

impl ChopperInputFactoryBuilder {
    pub fn new() -> ChopperInputFactoryBuilder {
        ChopperInputFactoryBuilder {
            dc_factory: None,
            csv_input_config: None,
            user_source_factories: None,
            user_streaming_transports: None,
        }
    }

    pub fn with_dc_factory(mut self, dc_factory: Option<DCFactory>) -> Self {
        self.dc_factory = dc_factory;
        self
    }

    pub fn with_csv_input_config(mut self, csv_input_config: CSVInputConfig) -> Self {
        self.csv_input_config = Some(csv_input_config);
        self
    }

    pub fn with_user_source_factories(
        mut self,
        user_source_factories: Option<Vec<Box<ChopperSourceFactory>>>,
    ) -> Self {
        self.user_source_factories = user_source_factories;
        self
    }

    pub fn with_user_streaming_transports(
        mut self,
        user_streaming_transports: Option<Vec<Box<dyn StreamingTransport>>>,
    ) -> Self {
        self.user_streaming_transports = user_streaming_transports;
        self
    }

    pub fn build(self) -> Result<ChopperInputFactory> {
        let mut default_source_factories =
            create_default_source_factories(self.dc_factory, self.csv_input_config);
        let source_factories = match self.user_source_factories {
            Some(mut s) => {
                s.append(&mut default_source_factories);
                s
            }
            None => default_source_factories,
        };

        let loc_input_factory =
            LocationInputFactory::new(source_factories, self.user_streaming_transports);

        let dir_transports = create_default_dir_transports();
        let dir_input_factory = Box::new(SourceDirInputFactory::new(
            loc_input_factory.clone(),
            dir_transports,
        ));

        InputFactory::new(dir_input_factory, loc_input_factory)
    }
}
