use axum::{
    Json, Router,
    extract::{Path, State},
    response::IntoResponse,
    routing::{delete, post},
};
use tracing::{debug, instrument};

use crate::{
    database::db::Db,
    error::CmsError,
    repositories::sepawa_repository::SepawaRepository,
    types::sepawa::{
        Agenda, AgendaId, NewAgenda, NewPartner, NewPortrait, Partner, PartnerId, Portrait,
        PortraitId,
    },
};

pub fn sepawa_app(db: Db) -> Result<Router, CmsError> {
    debug!("Create sepawa app");

    let state = SepawaRepository { db };

    let router = Router::new()
        .route(
            "/cms-api/portrait",
            post(create_portrait)
                .put(update_portrait)
                .get(get_portraits),
        )
        .route("/cms-api/portrait/{portrait_id}", delete(delete_portrait))
        .route(
            "/cms-api/partner",
            post(create_partner).put(update_partner).get(get_partners),
        )
        .route("/cms-api/partner/{partner_id}", delete(delete_partner))
        .route(
            "/cms-api/agenda",
            post(create_agenda)
                .put(update_agenda)
                .get(get_agenda_entries),
        )
        .route("/cms-api/agenda/{agenda_id}", delete(delete_agenda))
        .with_state(state);

    Ok(router)
}

pub async fn create_agenda(
    State(sepawa_repository): State<SepawaRepository>,
    Json(new_agenda): Json<NewAgenda>,
) -> Result<impl IntoResponse, CmsError> {
    sepawa_repository.create_agenda(new_agenda)?;

    Ok(())
}

pub async fn update_agenda(
    State(sepawa_repository): State<SepawaRepository>,
    Json(agenda): Json<Agenda>,
) -> Result<impl IntoResponse, CmsError> {
    sepawa_repository.update_agenda(agenda)?;

    Ok(())
}

pub async fn delete_agenda(
    State(sepawa_repository): State<SepawaRepository>,
    Path(agenda_id): Path<AgendaId>,
) -> Result<impl IntoResponse, CmsError> {
    sepawa_repository.delete_agenda(agenda_id)?;

    Ok(())
}

pub async fn get_agenda_entries(
    State(sepawa_repository): State<SepawaRepository>,
) -> Result<Json<Vec<Agenda>>, CmsError> {
    let agenda_entries = sepawa_repository.get_agenda_entries()?;

    Ok(Json(agenda_entries))
}

pub async fn get_partners(
    State(sepawa_repository): State<SepawaRepository>,
) -> Result<Json<Vec<Partner>>, CmsError> {
    let partners = sepawa_repository.get_partners()?;

    Ok(Json(partners))
}

pub async fn delete_partner(
    State(sepawa_repository): State<SepawaRepository>,
    Path(partner_id): Path<PartnerId>,
) -> Result<impl IntoResponse, CmsError> {
    sepawa_repository.delete_partner(partner_id)?;

    Ok(())
}

pub async fn update_partner(
    State(sepawa_repository): State<SepawaRepository>,
    Json(partner): Json<Partner>,
) -> Result<(), CmsError> {
    sepawa_repository.update_partner(partner)?;

    Ok(())
}

pub async fn create_partner(
    State(sepawa_repository): State<SepawaRepository>,
    Json(new_partner): Json<NewPartner>,
) -> Result<impl IntoResponse, CmsError> {
    debug!("Create a new Partner");
    sepawa_repository.create_partner(new_partner)?;

    Ok(())
}

pub async fn create_portrait(
    State(sepawa_repository): State<SepawaRepository>,
    Json(new_portrait): Json<NewPortrait>,
) -> Result<impl IntoResponse, CmsError> {
    sepawa_repository.create_portrait(new_portrait)?;

    Ok(())
}

pub async fn get_portraits(
    State(sepawa_repository): State<SepawaRepository>,
) -> Result<Json<Vec<Portrait>>, CmsError> {
    let portraits = sepawa_repository.get_portraits()?;

    Ok(Json(portraits))
}

pub async fn delete_portrait(
    State(sepawa_repository): State<SepawaRepository>,
    Path(portrait_id): Path<PortraitId>,
) -> Result<impl IntoResponse, CmsError> {
    sepawa_repository.delete_portrait(portrait_id)?;

    Ok(())
}

pub async fn update_portrait(
    State(sepawa_repository): State<SepawaRepository>,
    Json(portrait): Json<Portrait>,
) -> Result<impl IntoResponse, CmsError> {
    sepawa_repository.update_portrait(portrait)?;

    Ok(())
}
