pub mod deletes;
pub mod incremental;
pub mod index_tracer;
pub mod meta;

use serde::{Deserialize, Serialize};

pub const STORAGE_META_PATH: &str = "fts-data/tantivy/storages";
pub const INCREMENTAL_META_PATH: &str = "fts-data/tantivy/indexes";
pub const INCREMENTAL_INDEX_PATH: &str = INCREMENTAL_META_PATH;

// Schema-version 采用两段式 {big}.{small},
// 同一 big 版本下，small 版本数据向下兼容，不同 big 版本数据不兼容。
// big 版本变更自动触发下次重建索引为全量。
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SchemaVersion(f32);

impl SchemaVersion {
    fn big(&self) -> u64 {
        self.0 as u64
    }

    fn small(&self) -> u64 {
        let decimal_part = self.0.fract();
        (decimal_part * 1_000_000.0) as u64
    }

    pub fn contains(&self, other: &Self) -> bool {
        self.big() == other.big() && self.small() >= other.small()
    }
}

impl From<f32> for SchemaVersion {
    fn from(value: f32) -> Self {
        SchemaVersion(value)
    }
}

impl From<SchemaVersion> for f32 {
    fn from(version: SchemaVersion) -> f32 {
        version.0
    }
}

impl PartialEq for SchemaVersion {
    fn eq(&self, other: &Self) -> bool {
        self.0 == other.0
    }
}

impl Eq for SchemaVersion {}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_schema_version_contains() {
        let version1 = SchemaVersion(1.23);
        let version2 = SchemaVersion(1.23);
        let version3 = SchemaVersion(1.11);
        let version4: SchemaVersion = 1.3.into();
        assert!(version1.contains(&version2));
        assert!(version1.contains(&version3));
        assert!(!version1.contains(&version4));
    }

    #[test]
    fn test_schema_version_from_f32() {
        let version: SchemaVersion = 1.23.into();
        assert_eq!(version.0, 1.23);
    }

    #[test]
    fn test_schema_version_into_f32() {
        let version = SchemaVersion(1.23);
        let value: f32 = version.into();
        assert_eq!(value, 1.23);
    }
}
