use crate::op::{BinaryOpKind, JoinKind, OpRef, ReduceKind, UnaryOpKind};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ColumnSelector {
    All,
    Names(Vec<String>),
    Indices(Vec<usize>),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Literal {
    F64(f64),
    String(String),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Op {
    BinaryOp {
        kind: BinaryOpKind,
        lhs: OpRef,
        rhs: OpRef,
    },

    Reduce {
        kind: ReduceKind,
        on: OpRef,
    },

    UnaryOp {
        kind: UnaryOpKind,
        on: OpRef,
    },

    Filter {
        on: OpRef,
        mask: OpRef,
    },

    Where {
        mask: OpRef,
        then: OpRef,
        else_: OpRef,
    },

    Columns {
        on: Option<OpRef>,
        index: usize,
        selector: ColumnSelector,
    },

    Slice {
        on: OpRef,
        start: Option<isize>,
        end: Option<isize>,
    },

    Output {
        name: String,
        value: OpRef,
    },

    Constant {
        value: Literal,
    },

    Rolling {
        on: OpRef,
        n: usize,
    },

    Concat {
        who: Vec<OpRef>, // todo: Remove Alloc,
    },

    GroupBy {
        keys: OpRef,
        values: OpRef,
    },

    GroupReduce {
        keys: OpRef,
        values: OpRef,
        kinds: Vec<ReduceKind>,
    },

    Join {
        left: OpRef,
        right: OpRef,
        left_on: OpRef,
        right_on: OpRef,
        kind: JoinKind,
    },

    OrderBy {
        what: OpRef,
        by: OpRef,
        ascending: bool,
    },
}
