//! Blame/annotate view for files.
//!
//! Covers one route: `/{repo}/commits/{sha}/blame/{*path}`.  The handler
//! resolves the file at `{sha}:{path}` and runs `gix`'s blame algorithm to
//! attribute each line to the commit that last modified it.  Results are
//! displayed in a three-column table: commit SHA, line number, and code
//! content (cgit style).

use askama::Template;
use askama_web::WebTemplate;
use axum::extract::{Path, State};
use axum::response::IntoResponse;
use serde::Deserialize;

use crate::config::SiteConfig;
use crate::error::Result;
use crate::git;
use crate::routes::{AppState, Breadcrumb, RepoName};

/// Path parameters for the blame route.
#[derive(Deserialize)]
pub(super) struct BlamePath {
    sha: String,
    path: String,
}

/// Template data for the blame page.
#[derive(Template, WebTemplate)]
#[template(path = "blame.html")]
struct BlameView {
    repo: String,
    sha: String,
    path: String,
    tree_url: String,
    breadcrumbs: Vec<Breadcrumb>,
    lines: Vec<git::BlameEntry>,
    site: std::sync::Arc<SiteConfig>,
}

/// Renders the blame view for a file.
pub async fn handler(
    State(state): State<AppState>,
    RepoName(name): RepoName,
    Path(params): Path<BlamePath>,
) -> Result<impl IntoResponse> {
    git::validate_path(&params.path)?;

    let git_repo = git::open_repo(&state.root, &name)?;
    let lines = git::load_blame(&git_repo, &params.sha, &params.path)?;

    let b = &state.site.base_url;
    let tree_url = format!("{b}/{name}/commits/{}/tree/{}", params.sha, params.path);
    let breadcrumbs = crate::routes::build_breadcrumbs(b, &name, &params.sha, &params.path);

    Ok(BlameView {
        repo: name,
        sha: params.sha,
        path: params.path,
        tree_url,
        breadcrumbs,
        lines,
        site: state.site,
    })
}
