// trifid-api, an open source reimplementation of the Defined Networking nebula management server.
//     Copyright (C) 2023 c0repwn3r
//
//     This program is free software: you can redistribute it and/or modify
//     it under the terms of the GNU General Public License as published by
//     the Free Software Foundation, either version 3 of the License, or
//     (at your option) any later version.
//
//     This program is distributed in the hope that it will be useful,
//     but WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//     GNU General Public License for more details.
//
//     You should have received a copy of the GNU General Public License
//     along with this program.  If not, see <https://www.gnu.org/licenses/>.

use std::error::Error;

use rocket::form::validate::Contains;
use sqlx::PgPool;
use trifid_pki::ca::NebulaCAPool;

pub async fn get_org_by_owner_id(user: i32, db: &PgPool) -> Result<Option<i32>, Box<dyn Error>> {

    Ok(sqlx::query!("SELECT id FROM organizations WHERE owner = $1", user).fetch_optional(db).await?.map(|r| r.id))
}

pub async fn get_orgs_by_assoc_id(user: i32, db: &PgPool) -> Result<Vec<i32>, Box<dyn Error>> {
    let res: Vec<_> = sqlx::query!("SELECT org_id FROM organization_authorized_users WHERE user_id = $1", user).fetch_all(db).await?;

    let mut ret = vec![];

    for i in res {
        ret.push(i.org_id);
    }

    Ok(ret)
}

pub async fn get_users_by_assoc_org(org: i32, db: &PgPool) -> Result<Vec<i32>, Box<dyn Error>> {
    let res: Vec<_> = sqlx::query!("SELECT user_id FROM organization_authorized_users WHERE org_id = $1", org).fetch_all(db).await?;

    let mut ret = vec![];

    for i in res {
        ret.push(i.user_id);
    }

    Ok(ret)
}

pub async fn get_associated_orgs(user: i32, db: &PgPool) -> Result<Vec<i32>, Box<dyn Error>> {
    let mut assoc_orgs = vec![];

    if let Some(owned_org) = get_org_by_owner_id(user, db).await? {
        assoc_orgs.push(owned_org);
    }

    assoc_orgs.append(&mut get_orgs_by_assoc_id(user, db).await?);

    Ok(assoc_orgs)
}

pub async fn user_has_org_assoc(user: i32, org: i32, db: &PgPool) -> Result<bool, Box<dyn Error>> {
    let associated_orgs = get_associated_orgs(user, db).await?;

    Ok(associated_orgs.contains(org))
}

pub async fn get_org_ca_pool(org: i32, db: &PgPool) -> Result<NebulaCAPool, Box<dyn Error>> {
    // get CAPool PEM from db
    let pem = sqlx::query!("SELECT ca_crt FROM organizations WHERE id = $1", org).fetch_one(db).await?.ca_crt;

    let ca_pool = NebulaCAPool::new_from_pem(&hex::decode(pem)?)?;

    Ok(ca_pool)
}