use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use crate::error::{SKError, SKResult};

/// Statistics sidecar written alongside each SuperKmer file on close.
///
/// The sidecar path is `<file>.meta` (e.g. `raw.skmer.zst.meta`).
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SKFileMeta {
    /// Number of SuperKmer records in the file.
    pub instances: u64,
    /// Sum of all occurrence counts across records.
    pub count_sum: u64,
    /// Sum of all sequence lengths (in nucleotides) across records.
    pub length_sum: u64,
}

impl SKFileMeta {
    pub(crate) fn zero() -> Self {
        Self { instances: 0, count_sum: 0, length_sum: 0 }
    }

    /// Path of the sidecar file for a given SuperKmer file path.
    pub fn sidecar_path(sk_path: &Path) -> PathBuf {
        crate::append_path_suffix(sk_path, ".meta")
    }

    /// Read the sidecar for `sk_path`. Returns `None` if the sidecar is absent.
    pub fn read(sk_path: &Path) -> SKResult<Option<Self>> {
        let path = Self::sidecar_path(sk_path);
        match std::fs::File::open(&path) {
            Ok(f) => Ok(Some(serde_json::from_reader(f).map_err(|e| SKError::InvalidData {
                context: "SKFileMeta sidecar",
                detail: e.to_string(),
            })?)),
            Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(None),
            Err(e) => Err(e.into()),
        }
    }

    pub(crate) fn write(&self, sk_path: &Path) -> SKResult<()> {
        let path = Self::sidecar_path(sk_path);
        let f = std::fs::File::create(&path)?;
        serde_json::to_writer_pretty(f, self).map_err(|e| SKError::InvalidData {
            context: "SKFileMeta sidecar",
            detail: e.to_string(),
        })?;
        Ok(())
    }
}
