use axum::{http::StatusCode, response::{Html, IntoResponse, Response}};

#[derive(Debug, thiserror::Error)]
pub enum UiError {
    #[error("template render error: {0}")]
    Render(#[from] tera::Error),
    #[error("ui not configured — daemon built without embedded templates")]
    NotConfigured,
    #[error("project root not set — start daemon with --project-root")]
    NoProjectRoot,
    #[error("tool invocation failed: {0}")]
    Tool(String),
    #[error("io error: {0}")]
    Io(#[from] std::io::Error),
}

impl IntoResponse for UiError {
    fn into_response(self) -> Response {
        let status = match &self {
            UiError::NotConfigured | UiError::NoProjectRoot => StatusCode::SERVICE_UNAVAILABLE,
            _ => StatusCode::INTERNAL_SERVER_ERROR,
        };
        let detail = self.to_string();
        // Log the full source chain so the root cause is visible in logs.
        let mut cause_chain = String::new();
        if let Self::Render(ref e) = self {
            let mut src: &dyn std::error::Error = e;
            while let Some(next) = src.source() {
                use std::fmt::Write as _;
                let _ = write!(cause_chain, " → {next}");
                src = next;
            }
        }
        tracing::error!(ui_error = %detail, cause = %cause_chain, "UI handler error");
        let escaped = detail
            .replace('&', "&amp;")
            .replace('<', "&lt;")
            .replace('>', "&gt;")
            .replace('"', "&quot;");
        let html = format!(
            r#"<!DOCTYPE html>
<html data-theme="dark">
<head><meta charset="UTF-8"><title>UI Error</title>
<link rel="stylesheet" href="/public/css/provisioning.css"></head>
<body class="p-8 bg-base-100">
<div class="alert alert-error max-w-2xl">
  <pre class="font-mono text-sm whitespace-pre-wrap">{escaped}</pre>
</div>
</body></html>"#
        );
        (status, Html(html)).into_response()
    }
}
