use std::sync::Arc;

use bt_data::{DataStore, ParquetDataStore};
use pyo3::exceptions::PyRuntimeError;
use pyo3::prelude::*;

#[pyclass(name = "DataStore")]
#[derive(Clone)]
pub struct PyDataStore {
    data_root: String,
    metadata_db: String,
    dataset: String,
    store: Arc<ParquetDataStore>,
}

#[pymethods]
impl PyDataStore {
    #[new]
    #[pyo3(signature = (data_root, metadata_db="metadata/metadata.sqlite".to_string(), dataset="bars_1m".to_string()))]
    pub fn new(data_root: String, metadata_db: String, dataset: String) -> PyResult<Self> {
        let store = ParquetDataStore::with_dataset(&data_root, &metadata_db, &dataset)
            .map_err(|err| PyRuntimeError::new_err(format!("failed to open data store: {err}")))?;
        Ok(Self {
            data_root,
            metadata_db,
            dataset,
            store: Arc::new(store),
        })
    }

    pub fn data_root(&self) -> String {
        self.data_root.clone()
    }

    pub fn metadata_db(&self) -> String {
        self.metadata_db.clone()
    }

    pub fn dataset(&self) -> String {
        self.dataset.clone()
    }

    pub fn active_version(&self, dataset: &str) -> PyResult<String> {
        let version = self
            .store
            .active_version(dataset)
            .map_err(super::map_bt_error)?;
        Ok(version.id)
    }

    pub fn list_versions(&self, dataset: &str) -> PyResult<Vec<String>> {
        let versions = self
            .store
            .list_versions(dataset)
            .map_err(super::map_bt_error)?;
        Ok(versions.into_iter().map(|version| version.id).collect())
    }

    /// Resolve a ticker name (e.g. "BTCUSDT") to its integer SymbolId.
    pub fn resolve_symbol(&self, ticker: &str) -> PyResult<u32> {
        let infos = self
            .store
            .metadata_store()
            .list_symbol_infos()
            .map_err(super::map_bt_error)?;
        for info in &infos {
            if info.ticker.eq_ignore_ascii_case(ticker) {
                return Ok(info.id.0);
            }
        }
        Err(pyo3::exceptions::PyValueError::new_err(format!(
            "symbol '{ticker}' not found in metadata store"
        )))
    }

    /// List all symbols as (id, ticker) tuples.
    pub fn list_symbols(&self) -> PyResult<Vec<(u32, String)>> {
        let infos = self
            .store
            .metadata_store()
            .list_symbol_infos()
            .map_err(super::map_bt_error)?;
        Ok(infos
            .into_iter()
            .map(|info| (info.id.0, info.ticker))
            .collect())
    }
}

impl PyDataStore {
    pub(crate) fn store(&self) -> &Arc<ParquetDataStore> {
        &self.store
    }
}
