use anyhow::Result;
use log::*;
use std::sync::Arc;

use crate::storage::{incremental::IncrementalIndexMeta, meta::StorageMeta, STORAGE_META_PATH};

pub struct Deletes;

impl Deletes {
    pub async fn upload_deleteds(
        version: u64,
        cloud: Arc<dyn cloud::Storage>,
        deleteds: Vec<String>,
    ) -> Result<()> {
        if deleteds.is_empty() {
            info!("No deleteds to upload");
            return Ok(());
        }

        let key = format!("{}/deleteds/{}.json", STORAGE_META_PATH, version);
        cloud
            .upload_string(&key, &serde_json::to_string(&deleteds)?)
            .await?;
        info!("Uploaded {} deleteds to {}", deleteds.len(), key);
        Ok(())
    }

    pub async fn load_deleteds(cloud: Arc<dyn cloud::Storage>) -> Result<Vec<String>> {
        let keys = cloud
            .list_files(&format!("{}/deleteds/", STORAGE_META_PATH))
            .await?;
        let mut deleteds = vec![];
        for key in keys {
            let deleteds_str = cloud.read_file(&key).await?;
            let deleteds_vec: Vec<String> = serde_json::from_str(&deleteds_str)?;
            deleteds.extend(deleteds_vec);
        }

        Ok(deleteds)
    }

    pub async fn reset_deletes(cloud: Arc<dyn cloud::Storage>) -> Result<()> {
        let keys = cloud
            .list_files(&format!("{}/deleteds/", STORAGE_META_PATH))
            .await?;
        for key in keys {
            cloud.delete_file(&key).await?;
        }

        Ok(())
    }

    pub async fn gc(cloud: Arc<dyn cloud::Storage>, version: u64) -> Result<()> {
        info!("GC storage-meta for version {}", version);

        let storage_meta = StorageMeta::load_from_cloud_by_version(cloud.clone(), version).await?;
        storage_meta.delete_from_cloud(cloud.clone()).await?;

        for (index_name, index) in storage_meta.indexes {
            for incremental in index.incrementals {
                let mut incremental_meta = IncrementalIndexMeta::default();
                incremental_meta.set_meta(
                    index_name.clone(),
                    incremental.start_version,
                    incremental.end_version,
                    index.schema_version.clone(),
                );
                incremental_meta.delete(cloud.clone()).await?;
            }
        }

        Ok(())
    }
}
