use pyo3::prelude::*;
use radiate_python::{
    _activation_ops, _all_ops, _create_op, _edge_ops, _get_dtype_max, _get_dtype_min, PyAccuracy,
    PyBitCodec, PyCharCodec, PyChromosome, PyEcosystem, PyEngine, PyEngineBuilder, PyEngineEvent,
    PyEngineInput, PyEngineInputType, PyEngineRunOption, PyFitnessFn, PyFloatCodec, PyFront,
    PyFrontValue, PyGene, PyGeneType, PyGeneration, PyGenotype, PyGraph, PyGraphCodec, PyIntCodec,
    PyMetric, PyMetricSet, PyOp, PyPermutationCodec, PyPhenotype, PyPopulation, PyRandomProvider,
    PyRate, PySpecies, PySubscriber, PyTree, PyTreeCodec, py_accuracy, py_alter, py_select,
};

#[pyfunction]
pub fn py_version() -> &'static str {
    env!("CARGO_PKG_VERSION")
}

#[pymodule(gil_used = false)]
fn radiate(m: &Bound<'_, PyModule>) -> PyResult<()> {
    radiate_python::init_logging();

    m.add_function(wrap_pyfunction!(py_version, m)?)?;
    m.add_function(wrap_pyfunction!(py_select, m)?)?;
    m.add_function(wrap_pyfunction!(py_alter, m)?)?;
    m.add_function(wrap_pyfunction!(py_accuracy, m)?)?;
    m.add_function(wrap_pyfunction!(_get_dtype_max, m)?)?;
    m.add_function(wrap_pyfunction!(_get_dtype_min, m)?)?;
    m.add_function(wrap_pyfunction!(_all_ops, m)?)?;
    m.add_function(wrap_pyfunction!(_activation_ops, m)?)?;
    m.add_function(wrap_pyfunction!(_edge_ops, m)?)?;
    m.add_function(wrap_pyfunction!(_create_op, m)?)?;

    m.add_class::<PyRandomProvider>()?;
    m.add_class::<PyFitnessFn>()?;

    m.add_class::<PyFront>()?;
    m.add_class::<PyFrontValue>()?;

    m.add_class::<PyGeneType>()?;
    m.add_class::<PyGene>()?;
    m.add_class::<PyPhenotype>()?;
    m.add_class::<PyChromosome>()?;
    m.add_class::<PyGenotype>()?;
    m.add_class::<PyPopulation>()?;
    m.add_class::<PySpecies>()?;
    m.add_class::<PyEcosystem>()?;

    m.add_class::<PyFloatCodec>()?;
    m.add_class::<PyIntCodec>()?;
    m.add_class::<PyCharCodec>()?;
    m.add_class::<PyBitCodec>()?;
    m.add_class::<PyGraphCodec>()?;
    m.add_class::<PyTreeCodec>()?;
    m.add_class::<PyPermutationCodec>()?;

    m.add_class::<PySubscriber>()?;
    m.add_class::<PyEngineEvent>()?;

    m.add_class::<PyGraph>()?;
    m.add_class::<PyTree>()?;
    m.add_class::<PyAccuracy>()?;
    m.add_class::<PyOp>()?;

    m.add_class::<PyEngineInputType>()?;
    m.add_class::<PyEngineInput>()?;
    m.add_class::<PyRate>()?;
    m.add_class::<PyEngineBuilder>()?;
    m.add_class::<PyEngine>()?;
    m.add_class::<PyEngineRunOption>()?;
    m.add_class::<PyGeneration>()?;

    m.add_class::<PyMetricSet>()?;
    m.add_class::<PyMetric>()?;

    Ok(())
}
