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

use sepora_core::{Calendar, Diary, Todo};

use crate::storage::Storage as InternalStorage;

#[cfg(feature = "local")]
use crate::local::LocalStorage as ImplLocal;

#[cfg(feature = "github")]
use crate::github::GithubStorage as ImplGithub;

/// Public storage service.
///
/// Use:
/// ```
/// use sepora_storage::StorageService;
/// let storage = StorageService::new();
/// ```
///
/// The selected backend depends on Cargo features:
/// - default: `local`
/// - `--features github`: GitHub backend
#[derive(Clone)]
pub struct StorageService {
    inner: Arc<dyn InternalStorage>,
}

impl StorageService {
    /// Construct service using feature-selected backend.
    pub fn new() -> Self {
        // backend: use feature flags
        #[cfg(feature = "local")]
        {
            let backend = ImplLocal::new("./data");
            return Self {
                inner: Arc::new(backend),
            };
        }

        #[cfg(all(not(feature = "local"), feature = "github"))]
        {
            let backend = ImplGithub::new_from_env();
            return Self {
                inner: Arc::new(backend),
            };
        }

        #[cfg(all(not(feature = "local"), not(feature = "github")))]
        {
            eprintln!(
                "[FATAL] No valid storage backend selected. \
                 Enable one of: `--features local`, `--features github`."
            );
            std::process::exit(1);
        }
    }

    /// Construct service manually from a backend (mainly for tests).
    pub fn from_backend<B>(backend: B) -> Self
    where
        B: InternalStorage + 'static,
    {
        Self {
            inner: Arc::new(backend),
        }
    }

    // ---------------- Todo ----------------
    pub async fn list_todos(&self) -> Result<Vec<Todo>> {
        self.inner.list_todos().await
    }
    pub async fn create_todo(&self, todo: Todo) -> Result<()> {
        self.inner.create_todo(todo).await
    }
    pub async fn update_todo(&self, todo: Todo) -> Result<()> {
        self.inner.update_todo(todo).await
    }
    pub async fn delete_todo(&self, id: &str) -> Result<()> {
        self.inner.delete_todo(id).await
    }

    // ---------------- Diary ----------------
    pub async fn list_diaries(&self) -> Result<Vec<Diary>> {
        self.inner.list_diaries().await
    }
    pub async fn create_diary(&self, diary: Diary) -> Result<()> {
        self.inner.create_diary(diary).await
    }
    pub async fn update_diary(&self, diary: Diary) -> Result<()> {
        self.inner.update_diary(diary).await
    }
    pub async fn delete_diary(&self, id: &str) -> Result<()> {
        self.inner.delete_diary(id).await
    }

    // ---------------- Calendar ----------------
    pub async fn list_calendars(&self) -> Result<Vec<Calendar>> {
        self.inner.list_calendars().await
    }
    pub async fn create_calendar(&self, cal: Calendar) -> Result<()> {
        self.inner.create_calendar(cal).await
    }
    pub async fn update_calendar(&self, cal: Calendar) -> Result<()> {
        self.inner.update_calendar(cal).await
    }
    pub async fn delete_calendar(&self, id: &str) -> Result<()> {
        self.inner.delete_calendar(id).await
    }
}
