use axum::{
    extract::State,
    http::{header, HeaderValue},
    response::IntoResponse,
};
use axum_extra::extract::Host;
use tower_cookies::{Cookie, Cookies};

use crate::{
    client_server::{
        extractors::PubkyHost, layers::authz::session_secret_from_cookies,
        routes::auth::configure_session_cookie, AppState,
    },
    persistence::sql::session::SessionRepository,
    shared::{HttpError, HttpResult},
};

pub async fn session(
    State(state): State<AppState>,
    cookies: Cookies,
    pubky: PubkyHost,
) -> HttpResult<impl IntoResponse> {
    state
        .user_service
        .get_or_http_error(pubky.public_key(), false)
        .await?;

    if let Some(secret) = session_secret_from_cookies(&cookies, pubky.public_key()) {
        if let Ok(session) =
            SessionRepository::get_by_secret(&secret, &mut state.sql_db.pool().into()).await
        {
            let legacy_session = session.to_legacy();
            let mut resp = legacy_session.serialize().into_response();
            resp.headers_mut().insert(
                header::CONTENT_TYPE,
                HeaderValue::from_static("application/octet-stream"),
            );
            resp.headers_mut()
                .insert(header::VARY, HeaderValue::from_static("cookie, pubky-host"));
            resp.headers_mut().insert(
                header::CACHE_CONTROL,
                HeaderValue::from_static("private, must-revalidate"),
            );
            return Ok(resp);
        };
    }

    Err(HttpError::not_found())
}
pub async fn signout(
    State(state): State<AppState>,
    cookies: Cookies,
    Host(host): Host,
    pubky: PubkyHost,
) -> HttpResult<impl IntoResponse> {
    if let Some(secret) = session_secret_from_cookies(&cookies, pubky.public_key()) {
        SessionRepository::delete(&secret, &mut state.sql_db.pool().into()).await?;
    }

    // Always instruct the client to drop the session cookie, even if the
    // database record was already gone. This keeps repeated signout calls
    // idempotent and lets browsers wipe stale cookies immediately.
    let mut removal = Cookie::new(pubky.public_key().z32(), String::new());
    removal.make_removal();
    configure_session_cookie(&mut removal, &host);
    cookies.add(removal);

    // Idempotent Success Response (200 OK)
    Ok(())
}
