use ::scah::{Query, QueryMultiplexer, Reader, XHtmlParser};
use pyo3::prelude::*;

use std::sync::Arc;

mod element;
mod query;
mod save;

use crate::query::{PyQuery, PyQueryBuilder, PyQueryFactory, PyQueryStatic};
use crate::save::PySave;
use element::{PyElement, PyStore};

#[pyfunction]
fn parse<'py>(html: String, queries: Vec<PyRef<PyQuery>>) -> PyResult<PyStore> {
    let html = Arc::new(html);
    let html_bytes = html.as_ref().as_bytes();
    let html_bytes = unsafe { std::slice::from_raw_parts(html_bytes.as_ptr(), html_bytes.len()) };

    let queries_rs = queries
        .iter()
        .map(|q| q.query.clone())
        .collect::<Box<[Query]>>();

    let slice = unsafe {
        std::slice::from_raw_parts(queries_rs.as_ref().as_ptr(), queries_rs.as_ref().len())
    };
    let selectors = QueryMultiplexer::new(slice);
    let mut parser = XHtmlParser::with_capacity(selectors, html_bytes.len());

    let mut reader = Reader::from_bytes(html_bytes);
    while parser.next(&mut reader) {}

    let store = std::sync::Arc::new(parser.matches());

    Ok(PyStore { store, _html: html })
}

#[pymodule]
fn scah(m: &Bound<'_, PyModule>) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(parse, m)?)?;
    m.add_class::<PySave>()?;
    m.add_class::<PyQuery>()?;
    m.add_class::<PyQueryBuilder>()?;
    m.add_class::<PyQueryStatic>()?;
    m.add_class::<PyQueryFactory>()?;
    m.add_class::<PyElement>()?;
    m.add_class::<PyStore>()?;
    Ok(())
}
