use std::fmt::Debug;

use super::selection::QueryExecutor;
use crate::XHtmlElement;
use crate::css::selector::Query;
use crate::store::Store;

pub(crate) struct DocumentPosition {
    pub reader_position: usize,
    pub text_content_position: usize,
    pub element_depth: crate::selection_engine::DepthSize,
}

//type Runner<'query, E> = SmallVec<[QueryExecutor<'query, 'query, E>; 1]>;
type Runner<'query> = Vec<QueryExecutor<'query, 'query>>;

#[derive(Debug)]
pub struct QueryMultiplexer<'query> {
    runners: Runner<'query>,
}

impl<'html, 'query: 'html> QueryMultiplexer<'query> {
    pub fn new(queries: &'query [Query<'query>]) -> Self {
        Self {
            runners: queries
                .iter()
                .map(|query| QueryExecutor::new(query))
                .collect::<Runner<'query>>(),
        }
    }

    pub(crate) fn next(
        &mut self,
        xhtml_element: &XHtmlElement<'html>,
        position: &DocumentPosition,
        store: &mut Store<'html, 'query>,
    ) {
        let len = store.elements.len();
        for session in self.runners.iter_mut() {
            let _ = session.next(&xhtml_element, position, store);
        }
        if len == store.elements.len() {
            // Element was not saved
            // Thus delete from the tape
            xhtml_element.remove_attributes(&mut store.attributes);
        }
    }

    pub(crate) fn back(
        &mut self,
        xhtml_element: &'html str,
        position: &DocumentPosition,
        reader: &crate::utils::Reader<'html>,
        store: &mut Store<'html, 'query>,
    ) -> bool {
        let mut remove_indices = vec![];
        for (index, session) in self.runners.iter_mut().enumerate() {
            let early_exit = session.early_exit();
            let back = session.back(store, xhtml_element, position, reader);

            if early_exit && back {
                remove_indices.push(index);
            }
        }
        for idx in remove_indices {
            self.runners.remove(idx);
        }

        self.runners.is_empty()
    }
}

#[cfg(test)]
mod tests {
    use crate::{Query, QueryMultiplexer, Save, Store};

    use super::super::selection::QueryExecutor;
    use smallvec::SmallVec;

    #[test]
    fn runner_size() {
        println!(
            "Vec size: {}",
            std::mem::size_of::<Vec<QueryExecutor<'static, 'static>>>()
        );
        println!(
            "Inline size: {}",
            std::mem::size_of::<SmallVec<[QueryExecutor<'static, 'static>; 1]>>()
        );
    }

    #[test]
    fn test_single_element_query() {
        let query = Query::first("a", Save::all()).build();
        let q = &[query];
        let manager = QueryMultiplexer::new(q);
    }
}
