use crate::{
    Result, Rudof,
    api::data::implementations::{
        dereference, list_endpoints, load_data, load_service_description, reset_data, reset_service_description,
        serialize_data, serialize_service_description, show_node_info,
    },
    formats::{
        DataFormat, DataReaderMode, InputSpec, IriNormalizationMode, NodeInspectionMode, ResultDataFormat,
        ResultServiceFormat,
    },
};
use rudof_rdf::rdf_impl::EndpointStrategy;
use std::io;

/// Operations for managing RDF data.
pub trait DataOperations {
    /// Loads RDF data from one or more input sources.
    ///
    /// # Arguments
    ///
    /// * `data` - Optional array of input specifications defining data sources (uses None by default)
    /// * `data_format` - The RDF format of the input data (uses default if None)
    /// * `base` - Optional base IRI for resolving relative IRIs (uses default if None)
    /// * `endpoint` - Optional SPARQL endpoint URL to load data from. If stablished it overrides data (uses None by default)
    /// * `reader_mode` - The parsing mode (uses default if None)
    /// * `endpoint_strategy` - How `endpoint` (if given) answers lookups: SPARQL queries
    ///   or HTTP dereferencing. Ignored when `endpoint` is `None`.
    ///
    /// # Errors
    ///
    /// Returns an error if the data cannot be parsed or loaded.
    #[allow(clippy::too_many_arguments)]
    fn load_data(
        &mut self,
        data: Option<&[InputSpec]>,
        data_format: Option<&DataFormat>,
        base: Option<&str>,
        endpoint: Option<&str>,
        reader_mode: Option<&DataReaderMode>,
        merge: Option<bool>,
        prefixes: Option<&[InputSpec]>,
        endpoint_strategy: EndpointStrategy,
    ) -> Result<()>;

    /// Serializes the current RDF data to a writer.
    ///
    /// # Arguments
    ///
    /// * `result_data_format` - Optional output format (uses default if None)
    /// * `writer` - The destination to write the serialized data to
    ///
    /// # Errors
    ///
    /// Returns an error if serialization fails.
    fn serialize_data<W: io::Write>(
        &mut self,
        result_data_format: Option<&ResultDataFormat>,
        writer: &mut W,
    ) -> Result<()>;

    /// Resets the current data to an empty state.
    fn reset_data(&mut self);

    /// Loads a SPARQL service description from an input specification.
    ///
    /// # Arguments
    ///
    /// * `service` - Input specification defining the service description source
    /// * `data_format` - Optional format (uses default if None)
    /// * `reader_mode` - Optional parsing mode (uses default if None)
    /// * `base` - Optional base IRI for resolving relative IRIs in the service description (uses default if None)
    ///
    /// # Errors
    ///
    /// Returns an error if the service description cannot be parsed or loaded.
    fn load_service_description(
        &mut self,
        service: &InputSpec,
        data_format: Option<&DataFormat>,
        reader_mode: Option<&DataReaderMode>,
        base: Option<&str>,
    ) -> Result<()>;

    /// Serializes the current service description to a writer.
    ///
    /// # Arguments
    ///
    /// * `result_service_format` - Optional output format for the service description (uses default if None)
    /// * `writer` - The destination to write the serialized service description to
    ///
    /// # Errors
    ///
    /// Returns an error if no service description is loaded or serialization fails.
    fn serialize_service_description<W: io::Write>(
        &self,
        result_service_format: Option<&ResultServiceFormat>,
        writer: &mut W,
    ) -> Result<()>;

    /// Resets the current service description.
    fn reset_service_description(&mut self);

    /// Shows detailed information about a node in the current RDF data.
    ///
    /// # Arguments
    ///
    /// * `node` - Node identifier (IRI or prefixed name) to inspect
    /// * `predicates` - Optional list of predicates used to filter displayed relations
    /// * `show_node_mode` - Optional inspection mode controlling the level of detail (uses default if None)
    /// * `depth` - Optional maximum traversal depth when expanding related nodes (uses 1 by default)
    /// * `show_hyperlinks` - Whether hyperlinks should be included in the output (uses false by default)
    /// * `show_colors` - Whether colored output should be used (uses false by default)
    /// * `iri_mode` - IRI normalization mode to apply when parsing the node identifier
    /// * `writer` - The destination to write the node information to
    ///
    /// # Errors
    ///
    /// Returns an error if the node information cannot be retrieved or serialized.
    fn show_node_info<W: io::Write>(
        &mut self,
        node: &str,
        predicates: Option<&[String]>,
        show_node_mode: Option<&NodeInspectionMode>,
        depth: Option<usize>,
        show_hyperlinks: Option<bool>,
        show_colors: Option<bool>,
        iri_mode: IriNormalizationMode,
        writer: &mut W,
    ) -> Result<()>;

    /// Lists the registered SPARQL endpoints.
    ///
    /// Returns:
    ///     List of (name, url) tuples for known endpoints.
    fn list_endpoints(&mut self) -> Result<Vec<(String, String)>>;

    /// Dereferences `uri` over HTTP(S) and merges the resulting RDF data.
    ///
    /// Sends a GET request content-negotiating for an RDF serialization
    /// (`text/turtle`, `application/rdf+xml`, `application/ld+json`, ...),
    /// following redirects, and parses the response body using the format
    /// indicated by its `Content-Type` header (falling back to Turtle if the
    /// header is missing or unrecognized).
    ///
    /// # Arguments
    ///
    /// * `uri` - The absolute IRI to dereference
    /// * `reader_mode` - The parsing mode (uses default if None)
    /// * `merge` - Whether to merge with existing data or replace it (defaults to true)
    ///
    /// # Errors
    ///
    /// Returns an error if the request fails, the response status is not
    /// successful, or the body cannot be parsed as RDF.
    fn dereference(&mut self, uri: &str, reader_mode: Option<&DataReaderMode>, merge: Option<bool>) -> Result<()>;
}

impl DataOperations for Rudof {
    fn load_data(
        &mut self,
        data: Option<&[InputSpec]>,
        data_format: Option<&DataFormat>,
        base: Option<&str>,
        endpoint: Option<&str>,
        reader_mode: Option<&DataReaderMode>,
        merge: Option<bool>,
        prefixes: Option<&[InputSpec]>,
        endpoint_strategy: EndpointStrategy,
    ) -> Result<()> {
        load_data(
            self,
            data,
            data_format,
            base,
            endpoint,
            reader_mode,
            merge,
            prefixes,
            endpoint_strategy,
        )
    }

    fn serialize_data<W: io::Write>(
        &mut self,
        result_data_format: Option<&ResultDataFormat>,
        writer: &mut W,
    ) -> Result<()> {
        serialize_data(self, result_data_format, writer)
    }

    fn reset_data(&mut self) {
        reset_data(self)
    }

    fn load_service_description(
        &mut self,
        service: &InputSpec,
        data_format: Option<&DataFormat>,
        reader_mode: Option<&DataReaderMode>,
        base: Option<&str>,
    ) -> Result<()> {
        load_service_description(self, service, data_format, reader_mode, base)
    }

    fn serialize_service_description<W: io::Write>(
        &self,
        result_service_format: Option<&ResultServiceFormat>,
        writer: &mut W,
    ) -> Result<()> {
        serialize_service_description(self, result_service_format, writer)
    }

    fn reset_service_description(&mut self) {
        reset_service_description(self)
    }

    fn show_node_info<W: io::Write>(
        &mut self,
        node: &str,
        predicates: Option<&[String]>,
        show_node_mode: Option<&NodeInspectionMode>,
        depth: Option<usize>,
        show_hyperlinks: Option<bool>,
        show_colors: Option<bool>,
        iri_mode: IriNormalizationMode,
        writer: &mut W,
    ) -> Result<()> {
        show_node_info(
            self,
            node,
            predicates,
            show_node_mode,
            depth,
            show_hyperlinks,
            show_colors,
            iri_mode,
            writer,
        )
    }

    fn list_endpoints(&mut self) -> Result<Vec<(String, String)>> {
        list_endpoints(self)
    }

    fn dereference(&mut self, uri: &str, reader_mode: Option<&DataReaderMode>, merge: Option<bool>) -> Result<()> {
        dereference(self, uri, reader_mode, merge)
    }
}
