use chrono::{DateTime, Utc};
use redis::{AsyncCommands, RedisResult};
use serde::{Deserialize, Serialize};
use crate::db::redis_async_connection;
use crate::error::ApiResult;
use crate::metars::Metar;

#[derive(Debug, Serialize, Deserialize)]
pub struct MetarCheck {
  pub icao: String,
  pub status: bool,
  pub updated_at: DateTime<Utc>,
  pub last_metar: Option<Metar>,
}

impl MetarCheck {
  pub async fn new(icao: String, status: bool) -> Self {
    match Self::get(&icao).await {
      Some(c) => Self {
        icao,
        status,
        updated_at: Utc::now(),
        last_metar: c.last_metar,
      },
      None => Self {
        icao,
        status,
        updated_at: Utc::now(),
        last_metar: None,
      },
    }
  }

  pub async fn get(icao: &str) -> Option<MetarCheck> {
    let mut conn = match redis_async_connection().await {
      Ok(conn) => conn,
      Err(err) => {
        log::error!("{}", err);
        return None;
      }
    };
    let result: RedisResult<Option<String>> = conn.get(icao).await;
    match result {
      Ok(Some(value)) => match serde_json::from_str(&value) {
        Ok(result) => Some(result),
        Err(err) => {
          log::error!("{}", err);
          None
        }
      },
      Ok(None) => None,
      Err(err) => {
        log::error!("{}", err);
        None
      }
    }
  }

  pub async fn insert(&self, seconds: u64) -> ApiResult<()> {
    let mut conn = redis_async_connection().await?;
    let value = serde_json::to_string(&self)?;
    conn
      .set_ex::<_, _, ()>(self.icao.as_str(), value, seconds)
      .await?;

    Ok(())
  }
}
