// Copyright 2024, The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::convert::From;
use std::ops::DerefMut;
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;

use anyhow::Context;
use binder::Interface;
use binder::Result as BinderResult;
use log::error;
use mmd::os::MeminfoApiImpl;
use mmd::time::TimeApi;
use mmd::time::TimeApiImpl;
use mmd::zram::recompression::Error as ZramRecompressionError;
use mmd::zram::writeback::Error as ZramWritebackError;
use mmd::zram::SysfsZramApiImpl;
use mmd_aidl_interface::aidl::android::os::IMmd::IMmd;
use nix::sys::statvfs::statvfs;

use crate::properties::BoolProp;
use crate::properties::SecondsProp;
use crate::properties::U64Prop;
use crate::ZramContext;
use crate::ZRAM_WRITEBACK_FILE_PATH;

pub struct MmdService {
    ctx: Arc<Mutex<ZramContext>>,
}

impl MmdService {
    pub fn new(ctx: Arc<Mutex<ZramContext>>) -> Self {
        Self { ctx }
    }
}

impl Interface for MmdService {}

impl IMmd for MmdService {
    fn doZramMaintenance(&self) -> BinderResult<()> {
        let mut ctx = self.ctx.lock().expect("mmd aborts on panics");
        let ZramContext { zram_writeback, zram_recompression, suspend_history, .. } =
            ctx.deref_mut();

        // Execute recompression before writeback.
        if let Some(zram_recompression) = zram_recompression.as_mut() {
            let params = load_zram_recompression_params();
            match zram_recompression.mark_and_recompress::<SysfsZramApiImpl, MeminfoApiImpl>(
                &params,
                suspend_history,
                TimeApiImpl::get_boot_time(),
            ) {
                Ok(_) | Err(ZramRecompressionError::BackoffTime) => {}
                Err(e) => error!("failed to zram recompress: {e:?}"),
            }
        }

        if let Some(zram_writeback) = zram_writeback.as_mut() {
            let params = load_zram_writeback_params();
            let stats = match load_zram_writeback_stats() {
                Ok(v) => v,
                Err(e) => {
                    error!("failed to load zram writeback stats: {e:?}");
                    return Ok(());
                }
            };
            match zram_writeback.mark_and_flush_pages::<SysfsZramApiImpl, MeminfoApiImpl>(
                &params,
                &stats,
                suspend_history,
                TimeApiImpl::get_boot_time(),
            ) {
                Ok(_) | Err(ZramWritebackError::BackoffTime) | Err(ZramWritebackError::Limit) => {}
                Err(e) => error!("failed to zram writeback: {e:?}"),
            }
        }

        Ok(())
    }
}

fn load_zram_writeback_params() -> mmd::zram::writeback::Params {
    let mut params = mmd::zram::writeback::Params::default();
    params.backoff_duration = SecondsProp::ZramWritebackBackoff.get(params.backoff_duration);
    params.min_idle = SecondsProp::ZramWritebackMinIdle.get(params.min_idle);
    params.max_idle = SecondsProp::ZramWritebackMaxIdle.get(params.max_idle);
    params.huge_idle = BoolProp::ZramWritebackHugeIdleEnabled.get(params.huge_idle);
    params.idle = BoolProp::ZramWritebackIdleEnabled.get(params.idle);
    params.huge = BoolProp::ZramWritebackHugeEnabled.get(params.huge);
    params.min_bytes = U64Prop::ZramWritebackMinBytes.get(params.min_bytes);
    params.max_bytes = U64Prop::ZramWritebackMaxBytes.get(params.max_bytes);
    params.max_bytes_per_day = U64Prop::ZramWritebackMaxBytesPerDay.get(params.max_bytes_per_day);
    // min_free_diskspace_pct should be 0 ~ 100. If ZramWritebackMinFreeSpacePercentage is too big,
    // set 100% as fallback.
    params.min_free_diskspace_pct = U64Prop::ZramWritebackMinFreeSpacePercentage
        .get(params.min_free_diskspace_pct as u64)
        .try_into()
        .unwrap_or(100);
    params
}

fn load_zram_writeback_stats() -> anyhow::Result<mmd::zram::writeback::Stats> {
    let mm_stat =
        mmd::zram::stats::ZramMmStat::load::<SysfsZramApiImpl>().context("load mm_stat")?;
    let bd_stat =
        mmd::zram::stats::ZramBdStat::load::<SysfsZramApiImpl>().context("load bd_stat")?;
    let file_stat = statvfs(
        Path::new(ZRAM_WRITEBACK_FILE_PATH)
            .parent()
            .expect("parent of ZRAM_WRITEBACK_FILE_PATH must be not none."),
    )
    .context("statvfs writeback backing file")?;
    Ok(mmd::zram::writeback::Stats {
        orig_data_size: mm_stat.orig_data_size,
        current_writeback_pages: bd_stat.bd_count_pages,
        // libc::c_ulong and libc::fsblkcnt_t can be non-u64 on some platforms.
        #[allow(clippy::useless_conversion)]
        total_disksize: u64::from(file_stat.blocks()) * u64::from(file_stat.fragment_size()),
        // libc::c_ulong and libc::fsblkcnt_t can be non-u64 on some platforms.
        #[allow(clippy::useless_conversion)]
        free_disksize: u64::from(file_stat.blocks_free()) * u64::from(file_stat.block_size()),
    })
}

fn load_zram_recompression_params() -> mmd::zram::recompression::Params {
    let mut params = mmd::zram::recompression::Params::default();
    params.backoff_duration = SecondsProp::ZramRecompressionBackoff.get(params.backoff_duration);
    params.min_idle = SecondsProp::ZramRecompressionMinIdle.get(params.min_idle);
    params.max_idle = SecondsProp::ZramRecompressionMaxIdle.get(params.max_idle);
    params.huge_idle = BoolProp::ZramRecompressionHugeIdleEnabled.get(params.huge_idle);
    params.idle = BoolProp::ZramRecompressionIdleEnabled.get(params.idle);
    params.huge = BoolProp::ZramRecompressionHugeEnabled.get(params.huge);
    params.threshold_bytes = U64Prop::ZramRecompressionThresholdBytes.get(params.threshold_bytes);
    params
}
