use std::sync::Arc;
use chrono::{DateTime, Utc};
use uuid::Uuid;
use crate::error::{ApiResult, AppError};
use crate::model::auth::AccessToken;
use crate::repo::access_token_repo::AccessTokenRepo;
use crate::repo::AccessTokenRepoTrait;


#[derive(Clone)]
pub struct AccessTokenService {
	repo: Arc<dyn AccessTokenRepoTrait>
}

impl AccessTokenService {
	pub fn new(repo: Arc<dyn AccessTokenRepoTrait>) -> Self {
		Self { repo }
	}

	pub async fn create(&self,
		uid: i64, name: &str, max_uses: i32,
		valid_from: DateTime<Utc>, valid_until: DateTime<Utc>
	) -> ApiResult<String> {
		if valid_from > valid_until {
			return Err(AppError::bad_request("start date must be before end date"))
		}

		if valid_until < Utc::now() {
			return Err(AppError::bad_request("expiry date must be after current date"))
		}

		let code = Uuid::new_v4().to_string();
		self.repo.create_new(uid, name, &code, max_uses, valid_from, valid_until).await?;

		Ok(code)
	}

	pub async fn get_valid_token(&self, token: &str) -> ApiResult<AccessToken> {
		self.repo.get_code_not_expired(token).await?
			.ok_or(AppError::unauthorised("invalid access token"))
	}

	pub async fn use_token(&self, id: i64) -> ApiResult<()> {
		self.repo.use_token(id).await?;
		Ok(())
	}
}