use csscolorparser::Color;
use petgraph::{data::Build, prelude::NodeIndex};

use crate::{
    types::nodes::primitives::{
        blend::BlendMode,
        color_matrix::ColorMatrixType,
        component_transfer::TransferFn,
        displacement_map::Channel,
        turbulence::{NoiseType, StitchTiles},
    },
    Node,
};

use super::{FilterGraph, NodeInput};

impl FilterGraph {
    pub fn color_matrix(
        &mut self,
        r#in: impl Into<NodeInput>,
        cm_type: ColorMatrixType,
    ) -> NodeIndex {
        let node_idx = self.dag.add_node(Node::color_matrix(cm_type));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        node_idx
    }

    pub fn offset(&mut self, r#in: impl Into<NodeInput>, dx: f32, dy: f32) -> NodeIndex {
        let node_idx = self.dag.add_node(Node::offset(dx, dy));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        node_idx
    }

    pub fn gaussian_blur_xy(&mut self, r#in: impl Into<NodeInput>, x: u16, y: u16) -> NodeIndex {
        let node_idx = self.dag.add_node(Node::gaussian_blur_xy(x, y));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        node_idx
    }

    pub fn blend(
        &mut self,
        r#in: impl Into<NodeInput>,
        in2: impl Into<NodeInput>,
        mode: BlendMode,
    ) -> NodeIndex {
        let node_idx = self.dag.add_node(Node::blend(mode));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        self.dag
            .add_edge(self.resolve_input(in2.into()), node_idx, ());
        node_idx
    }

    pub fn composite_arithmetic(
        &mut self,
        r#in: impl Into<NodeInput>,
        in2: impl Into<NodeInput>,
        k1: f32,
        k2: f32,
        k3: f32,
        k4: f32,
    ) -> NodeIndex {
        let node_idx = self
            .dag
            .add_node(Node::composite_arithmetic(k1, k2, k3, k4));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        self.dag
            .add_edge(self.resolve_input(in2.into()), node_idx, ());
        node_idx
    }

    pub fn component_transfer_rgba(
        &mut self,
        r#in: impl Into<NodeInput>,
        r: TransferFn,
        g: TransferFn,
        b: TransferFn,
        a: TransferFn,
    ) -> NodeIndex {
        let node_idx = self.dag.add_node(Node::component_transfer_rgba(r, g, b, a));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        node_idx
    }
    pub fn component_transfer_rgb(
        &mut self,
        r#in: impl Into<NodeInput>,
        r: TransferFn,
        g: TransferFn,
        b: TransferFn,
    ) -> NodeIndex {
        let node_idx = self.dag.add_node(Node::component_transfer_rgb(r, g, b));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        node_idx
    }
    pub fn component_transfer_r(
        &mut self,
        r#in: impl Into<NodeInput>,
        func: TransferFn,
    ) -> NodeIndex {
        let node_idx = self.dag.add_node(Node::component_transfer_r(func));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        node_idx
    }
    pub fn component_transfer_g(
        &mut self,
        r#in: impl Into<NodeInput>,
        func: TransferFn,
    ) -> NodeIndex {
        let node_idx = self.dag.add_node(Node::component_transfer_g(func));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        node_idx
    }
    pub fn component_transfer_b(
        &mut self,
        r#in: impl Into<NodeInput>,
        func: TransferFn,
    ) -> NodeIndex {
        let node_idx = self.dag.add_node(Node::component_transfer_b(func));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        node_idx
    }
    pub fn component_transfer_a(
        &mut self,
        r#in: impl Into<NodeInput>,
        func: TransferFn,
    ) -> NodeIndex {
        let node_idx = self.dag.add_node(Node::component_transfer_a(func));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        node_idx
    }
    pub fn component_transfer_single(
        &mut self,
        r#in: impl Into<NodeInput>,
        func: TransferFn,
    ) -> NodeIndex {
        let node_idx = self.dag.add_node(Node::component_transfer_single(func));
        self.dag
            .add_edge(self.resolve_input(r#in.into()), node_idx, ());
        node_idx
    }

    pub fn flood(&mut self, flood_color: Color, flood_opacity: f32) -> NodeIndex {
        self.dag.add_node(Node::flood(flood_color, flood_opacity))
    }

    pub fn flood_opaque(&mut self, flood_color: Color) -> NodeIndex {
        self.dag.add_node(Node::flood_opaque(flood_color))
    }

    pub fn turbulence(
        &mut self,
        base_freq_x: f32,
        base_freq_y: f32,
        num_octaves: u16,
        seed: u32,
        stitch_tiles: StitchTiles,
        noise_type: NoiseType,
    ) -> NodeIndex {
        self.dag.add_node(Node::turbulence(
            base_freq_x,
            base_freq_y,
            num_octaves,
            seed,
            stitch_tiles,
            noise_type,
        ))
    }

    pub fn displacement_map(
        &mut self,
        source_image: impl Into<NodeInput>,
        displacement_map: impl Into<NodeInput>,
        scale: f32,
        x_channel: Channel,
        y_channel: Channel,
    ) -> NodeIndex {
        let node_idx = self
            .dag
            .add_node(Node::displacement_map(scale, x_channel, y_channel));
        self.dag
            .add_edge(self.resolve_input(source_image.into()), node_idx, ());
        self.dag
            .add_edge(self.resolve_input(displacement_map.into()), node_idx, ());
        node_idx
    }
}
