use crate::{
    Result, Rudof,
    api::generation::GenerationOperations,
    formats::{DataFormat, GenerationSchemaFormat, InputSpec},
};
use std::path::PathBuf;

/// Builder for `generate_data` operation.
///
/// Provides a fluent interface for configuring optional parameters for data
/// generation (result format, seed, parallelism) and executing the operation.
pub struct GenerateDataBuilder<'a> {
    rudof: &'a Rudof,
    schema: &'a InputSpec,
    schema_format: &'a GenerationSchemaFormat,
    output: Option<&'a PathBuf>,
    config_file: Option<&'a PathBuf>,
    result_generation_format: Option<&'a DataFormat>,
    number_entities: Option<usize>,
    seed: Option<u64>,
    parallel: Option<usize>,
}

impl<'a> GenerateDataBuilder<'a> {
    /// Create a new builder.
    ///
    /// Internal helper called by `Rudof::generate_data()`; not intended for
    /// direct public construction.
    pub(crate) fn new(
        rudof: &'a Rudof,
        schema: &'a InputSpec,
        schema_format: &'a GenerationSchemaFormat,
        number_entities: Option<usize>,
    ) -> Self {
        Self {
            rudof,
            schema,
            schema_format,
            result_generation_format: None,
            number_entities,
            seed: None,
            parallel: None,
            output: None,
            config_file: None,
        }
    }

    /// Set the desired output data format for the generated RDF.
    pub fn with_result_generation_format(mut self, result_generation_format: &'a DataFormat) -> Self {
        self.result_generation_format = Some(result_generation_format);
        self
    }

    /// Set an explicit random seed for reproducible generation.
    pub fn with_seed(mut self, seed: u64) -> Self {
        self.seed = Some(seed);
        self
    }

    /// Set number of parallel worker threads to use.
    pub fn with_parallel(mut self, parallel: usize) -> Self {
        self.parallel = Some(parallel);
        self
    }

    /// Set an optional output file path to write the generated RDF data.
    pub fn with_output(mut self, output: &'a PathBuf) -> Self {
        self.output = Some(output);
        self
    }

    /// Set a `GeneratorConfig` file (TOML or JSON) controlling generation
    /// details (entity distribution, cardinality strategy, per-field
    /// generators, ...) beyond what the other builder methods expose.
    ///
    /// CLI-style overrides set through this builder (`with_result_generation_format`,
    /// `with_output`, `with_seed`, `with_parallel`, and a `Some` passed as
    /// `number_entities` to [`Rudof::generate_data`]) take precedence over the
    /// same settings in the config file; a `None` `number_entities` leaves the
    /// config file's `entity_count` (or the generator's own default) in effect.
    pub fn with_config_file(mut self, config_file: &'a PathBuf) -> Self {
        self.config_file = Some(config_file);
        self
    }

    /// Execute data generation with the configured parameters.
    pub async fn execute(self) -> Result<()> {
        <Rudof as GenerationOperations>::generate_data(
            self.rudof,
            self.schema,
            self.schema_format,
            self.result_generation_format,
            self.output,
            self.config_file,
            self.number_entities,
            self.seed,
            self.parallel,
        )
        .await
    }
}
