// Copyright 2021 TiKV Project Authors. Licensed under Apache-2.0.
use std::{
    path::Path,
    sync::atomic::{AtomicI32, AtomicU64, Ordering},
};

use fail::fail_point;

// The following variables are used to store the disk capacity, used size, and
// available size.
static DISK_CAPACITY: AtomicU64 = AtomicU64::new(0);
static DISK_USED_SIZE: AtomicU64 = AtomicU64::new(0);
static DISK_AVAILABLE_SIZE: AtomicU64 = AtomicU64::new(0);

#[inline]
pub fn set_disk_capacity(v: u64) {
    DISK_CAPACITY.store(v, Ordering::Release)
}

#[inline]
pub fn get_disk_capacity() -> u64 {
    DISK_CAPACITY.load(Ordering::Acquire)
}

#[inline]
pub fn set_disk_used_size(v: u64) {
    DISK_USED_SIZE.store(v, Ordering::Release)
}

#[inline]
pub fn get_disk_used_size() -> u64 {
    DISK_USED_SIZE.load(Ordering::Acquire)
}

#[inline]
pub fn set_disk_available_size(v: u64) {
    DISK_AVAILABLE_SIZE.store(v, Ordering::Release)
}

#[inline]
pub fn get_disk_available_size() -> u64 {
    DISK_AVAILABLE_SIZE.load(Ordering::Acquire)
}

pub fn get_disk_space_stats<P: AsRef<Path>>(path: P) -> std::io::Result<(u64, u64)> {
    fail_point!("mock_disk_space_stats", |stats| {
        let stats = stats.ok_or_else(|| {
            std::io::Error::new(std::io::ErrorKind::InvalidInput, "missing disk_space_stats")
        })?;
        let values = stats.split(',').collect::<Vec<_>>();
        if values.len() < 2 {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidInput,
                "invalid disk_space_stats format",
            ));
        }
        Ok((
            values[0]
                .parse::<u64>()
                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?,
            values[1]
                .parse::<u64>()
                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?,
        ))
    });
    let disk_stats = fs2::statvfs(path)?;
    Ok((disk_stats.total_space(), disk_stats.available_space()))
}
