use crate::database::Database;
use crate::models::projects;
use crate::repoman::RepoMan;
use rocket::fs::NamedFile;
use rocket::{Route, State};
#[get("/<org_path>/<proj_path>/.pijul?<channel>&<id>", rank = 2)]
async fn remote_id(
    db: &State<Database>,
    repoman: &State<RepoMan>,
    org_path: String,
    proj_path: String,
    channel: String,     id: Option<String>,
) -> Option<String> {
    let p = match projects::find(db, org_path, proj_path).await {
        Some(p) => p,
        None => return None,
    };
    match p.repository(&repoman.storage_root) {
        Ok(r) => r.channel_remote_id(channel, id),
        Err(e) => {
            println!("{}", e);
            None
        }
    }
}
#[get("/<org_path>/<proj_path>/.pijul?<changelist>&<channel>")]
async fn changelist(
    db: &State<Database>,
    repoman: &State<RepoMan>,
    org_path: String,
    proj_path: String,
    channel: String,     changelist: u64,
) -> Option<String> {
    let p = projects::find(db, org_path, proj_path).await?;
    match p
        .repository(&repoman.storage_root)
        .unwrap()
        .changelist(channel, changelist)
    {
        Ok(out) => Some(out),
        Err(e) => {
            println!("error getting changelist: {}", e);
            None
        }
    }
}
use rocket::fs::TempFile;
#[post("/<org_path>/<proj_path>/.pijul?<apply>", data = "<patch>")]
async fn apply(
    db: &State<Database>,
    repoman: &State<RepoMan>,
    current_user: crate::models::users::User,
    org_path: String,
    proj_path: String,
    apply: String,
    mut patch: TempFile<'_>,
) -> rocket::http::Status {
    let p = if let Some(p) = projects::find(db, org_path, proj_path).await {
        p
    } else {
        return rocket::http::Status::NotFound;
    };
    let repo = p.repository(&repoman.storage_root).unwrap();
    let hash =
        if let Some(h) = crate::models::pijul::changestores::Changestore::hash_from_string(apply) {
            h
        } else {
            return rocket::http::Status::InternalServerError;
        };
    if !crate::authz::can_apply_patch(db, ¤t_user, &repo).await {
        return rocket::http::Status::Unauthorized;
    }
    let patch_path = repo.changestore().change_file(hash);
    if repo.changestore().ensure_parent_dirs(hash).is_err() {
        println!("No write permission?");
        return rocket::http::Status::InternalServerError;
    }
    if patch.persist_to(&patch_path).await.is_err() {
        return rocket::http::Status::InternalServerError;
    }
    if !repo.valid_change(hash) {
        println!("Not valid as object");
        return rocket::http::Status::InternalServerError;
    }
    if repo.apply_change_to_channel("main", hash).is_ok() {
        return rocket::http::Status::Accepted;
    };
    rocket::http::Status::InternalServerError
}
#[derive(FromForm)]
struct Identities {
    identities: Vec<String>,
}
use rocket::serde::{json::Json, Serialize};
#[derive(Serialize, FromForm)]
struct IdentitieRes {
    id: Vec<String>,
    rev: u64,
}
#[get("/<_>/<_>/.pijul?<identities>", rank = 4)]
fn identities(identities: Identities) -> Json<IdentitieRes> {
    println!("{:?}", identities.identities);
    Json(IdentitieRes { id: vec![], rev: 0 })
}
#[get("/<org_path>/<proj_path>/.pijul?<change>", rank = 3)]
async fn change(
    db: &State<Database>,
    repoman: &State<RepoMan>,
    org_path: String,
    proj_path: String,
    change: String,
) -> Option<NamedFile> {
    let p = projects::find(db, org_path, proj_path).await?;
    let hash = crate::models::pijul::changestores::Changestore::hash_from_string(change)?;
    let repo = p.repository(&repoman.storage_root).ok()?;
    let path = repo.changestore().change_file(hash);
    NamedFile::open(path).await.ok()
}
pub fn routes() -> Vec<Route> {
    routes![remote_id, changelist, apply, identities, change]
}