use crate::GitError;
use crate::hook::sync::HookMetaDataSync;

#[derive(Debug, Clone)]
pub enum SyncStatus {
    Pending,
    Processing,
    Success,
    Failed(String),
}

impl std::fmt::Display for SyncStatus {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            SyncStatus::Pending => write!(f, "pending"),
            SyncStatus::Processing => write!(f, "processing"),
            SyncStatus::Success => write!(f, "success"),
            SyncStatus::Failed(_) => write!(f, "failed"),
        }
    }
}

impl HookMetaDataSync {
    const STATUS_TTL_SECS: u64 = 86400;

    pub async fn update_sync_status(&self, status: SyncStatus) -> Result<(), GitError> {
        let key = format!("git:repo:sync_status:{}", self.repo.id);
        let status_str = status.to_string();

        let mut conn = self
            .cache
            .conn()
            .await
            .map_err(|e| GitError::IoError(format!("failed to get redis connection: {}", e)))?;

        let _: () = redis::cmd("SETEX")
            .arg(&key)
            .arg(Self::STATUS_TTL_SECS)
            .arg(&status_str)
            .query_async(&mut conn)
            .await
            .map_err(|e| GitError::IoError(format!("failed to set sync status: {}", e)))?;

        if let SyncStatus::Failed(ref error_msg) = status {
            let error_key = format!("git:repo:sync_error:{}", self.repo.id);
            let _: () = redis::cmd("SETEX")
                .arg(&error_key)
                .arg(Self::STATUS_TTL_SECS)
                .arg(error_msg)
                .query_async(&mut conn)
                .await
                .map_err(|e| GitError::IoError(format!("failed to set sync error: {}", e)))?;
        }

        Ok(())
    }

    pub async fn get_sync_status(&self) -> Result<Option<SyncStatus>, GitError> {
        let key = format!("git:repo:sync_status:{}", self.repo.id);
        let error_key = format!("git:repo:sync_error:{}", self.repo.id);

        let mut conn = self
            .cache
            .conn()
            .await
            .map_err(|e| GitError::IoError(format!("failed to get redis connection: {}", e)))?;

        let status_str: Option<String> =
            redis::cmd("GET")
                .arg(&key)
                .query_async(&mut conn)
                .await
                .map_err(|e| GitError::IoError(format!("failed to get sync status: {}", e)))?;

        match status_str {
            Some(status) => {
                let error_msg: Option<String> = redis::cmd("GET")
                    .arg(&error_key)
                    .query_async(&mut conn)
                    .await
                    .map_err(|e| GitError::IoError(format!("failed to get sync error: {}", e)))?;

                let sync_status = match status.as_str() {
                    "pending" => SyncStatus::Pending,
                    "processing" => SyncStatus::Processing,
                    "success" => SyncStatus::Success,
                    "failed" => {
                        SyncStatus::Failed(error_msg.unwrap_or_else(|| "Unknown error".to_string()))
                    }
                    _ => SyncStatus::Pending,
                };

                Ok(Some(sync_status))
            }
            None => Ok(None),
        }
    }
}
