use std::time::{SystemTime, Duration, UNIX_EPOCH};

use mysql_async::{params, Pool};
use mysql_async::prelude::Queryable;
use mysql_async::error::Error as SqlError;


use crate::{BigInt, Invite, Response};

impl Invite {
    pub async fn get(p: &Pool, id: BigInt) -> Result<Response<Self>, SqlError> {
        // NOTE: cast is required for this as `id` is used as unix timestamp
        let id: BigInt = id as BigInt; 

        if id <= 0 {
            return Ok(Response::RestrictedInput(format!("<{}> not found", id)))
        }

        let conn = p.get_conn().await?;
        let q = "SELECT uses, expires FROM invites WHERE id = :id ";
        let (_, data_row): (_, Option<(Option<BigInt>, bool)>) = 
            conn.first_exec(q, params!{"id" => id}).await?;

        return if let Some(row) = data_row {
            Ok(Response::Row(Invite{
                id,
                uses: row.0,
                expires: row.1,
            }))
        } else {
            Ok(Response::Empty)
        }
    }


    pub fn new(uses: Option<i64>, expires: bool) -> Invite {
        // now + 30 minutes
        let later = SystemTime::now() + Duration::from_secs(60 * 30);
        let id: i64 = later.duration_since(UNIX_EPOCH).expect("honestly idk").as_millis() as i64;
        
        Invite {
            id,
            uses,
            expires
        }
    }

    pub async fn add(&self, p: &Pool) -> Result<(), SqlError> {
        let conn = p.get_conn().await?;

        conn.prep_exec(
            "INSERT INTO invites (id, uses, expires)
            VALUES (:id, :uses, :expires)", params!{
                "id"    => self.id,
                "uses"  => self.uses,
                "expires" => self.expires
        }).await?;

        Ok(())
    }

}
