//! Request handlers for routing and fallback handling
//!
//! This module contains various request handlers including the fallback handler
//! for dynamic routes and other specialized request handling functions.

use axum::{
    extract::State,
    http::{HeaderMap, StatusCode},
    response::{IntoResponse, Response},
};
use rustelo_core_lib::routing::engine::resolve_route;

use crate::run::SiteOptions;
use crate::run::{render_route_response, render_ssr_with_context};
use crate::utils::htmx::{htmx_error_response, is_htmx_request};

/// Fallback handler for dynamic routes (blog posts, etc.).
///
/// Resolves the URL, applies language-redirect rules, then dispatches on
/// `(rendering_profile, HX-Request)` via [`render_route_response`].
pub async fn fallback_handler(
    State(site_options): State<SiteOptions>,
    headers: HeaderMap,
    uri: axum::http::Uri,
) -> Response {
    let path = uri.path();

    tracing::debug!("Fallback handler processing path: {}", path);

    let route_resolution = resolve_route(path);

    if route_resolution.exists {
        let detected_lang = crate::utils::lang_detection::detect_ssr_language(path, &headers);

        if let Some(localized_url) =
            crate::utils::lang_detection::check_language_redirect(path, &detected_lang, &headers)
        {
            tracing::debug!(
                "Redirecting {} to localized version ({}): {}",
                path,
                detected_lang,
                localized_url
            );
            // HTMX clients honour HX-Redirect for client-side navigation; everyone else
            // gets the standard 302 Location.
            let mut builder = axum::response::Response::builder().status(302);
            if is_htmx_request(&headers) {
                builder = builder.header("HX-Redirect", &localized_url);
            }
            return builder
                .header("Location", localized_url)
                .body(axum::body::Body::empty())
                .unwrap()
                .into_response();
        }

        tracing::debug!(
            "Route exists, rendering with profile {} for path {}",
            route_resolution.rendering_profile,
            path
        );
        // Inject the raw query string as a synthetic header so shell renderers
        // (e.g. the HTMX grid) can read filter/search params from direct URLs
        // like /blog?tag=rust&q=nush without requiring a framework API change.
        let mut augmented = headers.clone();
        if let Some(query) = uri.query() {
            if let Ok(value) = axum::http::HeaderValue::from_str(query) {
                augmented.insert(
                    axum::http::HeaderName::from_static("x-request-query"),
                    value,
                );
            }
        }
        render_route_response(site_options, &route_resolution, &augmented)
    } else {
        tracing::debug!("Route not found: {}", path);

        if is_htmx_request(&headers) {
            return htmx_error_response(
                &headers,
                StatusCode::NOT_FOUND,
                format!("Not found: {}", path),
            );
        }

        let not_found_html = render_ssr_with_context(site_options, Some("/not-found".to_string()));

        axum::response::Response::builder()
            .status(404)
            .header("Content-Type", "text/html; charset=utf-8")
            .body(axum::body::Body::from(not_found_html))
            .unwrap()
            .into_response()
    }
}
