use actix_web::HttpResponse;
use maud::{Markup, Render, html};

use super::{
    Page,
    components::{RepositoryChrome, RepositoryTab},
    repositories::RefSummary,
};

pub(super) struct RefsBody<'a> {
    owner: &'a str,
    slug: &'a str,
    visibility: &'a str,
    default_branch: &'a str,
    branches: &'a [RefSummary],
    tags: &'a [RefSummary],
    viewer: Option<&'a str>,
}

impl Render for RefsBody<'_> {
    fn render(&self) -> Markup {
        html! {
            (RepositoryChrome {
                owner: self.owner,
                slug: self.slug,
                visibility: self.visibility,
                default_branch: self.default_branch,
                current_tab: RepositoryTab::Refs,
                is_owner: self.viewer == Some(self.owner),
            })
            h3 { "Branches (" (self.branches.len()) ")" }
            (RefList {
                owner: self.owner,
                slug: self.slug,
                refs: self.branches,
            })
            h3 { "Tags (" (self.tags.len()) ")" }
            (RefList {
                owner: self.owner,
                slug: self.slug,
                refs: self.tags,
            })
        }
    }
}

/// A branch or tag listing, or a note that there is nothing to list.
pub(super) struct RefList<'a> {
    pub(super) owner: &'a str,
    pub(super) slug: &'a str,
    pub(super) refs: &'a [RefSummary],
}

impl Render for RefList<'_> {
    fn render(&self) -> Markup {
        html! {
            @if self.refs.is_empty() {
                p class="empty" { "Nothing here yet." }
            } @else {
                ul class="refs" {
                    @for reference in self.refs {
                        li {
                            // The name leads into the ref's commit history:
                            // a ref names a line of work, and the history
                            // is what that line says.
                            code class="ref-name" {
                                a href=(format!(
                                    "/~{}/{}/commits/{}",
                                    self.owner, self.slug, reference.name
                                )) {
                                    (reference.name)
                                }
                            }
                            // The hash beneath the name leads to the commit
                            // itself rather than to where the ref stands:
                            // what a hash names is a moment, and it is
                            // addressed by its full self.
                            code class="hash" {
                                a href=(format!(
                                    "/~{}/{}/commit/{}",
                                    self.owner, self.slug, reference.full_hash
                                )) {
                                    (reference.hash)
                                }
                            }
                            span class="author" { (reference.author) }
                            span class="subject" { (reference.subject) }
                        }
                    }
                }
            }
        }
    }
}

/// The page listing every branch and tag of `owner`'s repository `slug`.
pub fn refs(
    viewer: Option<&str>,
    owner: &str,
    slug: &str,
    visibility: &'static str,
    default_branch: &str,
    branches: &[RefSummary],
    tags: &[RefSummary],
) -> HttpResponse {
    Page {
        title: format!("~{owner}/{slug}: Refs - Frogue"),
        viewer: viewer.map(str::to_string),
        extra_head: None,
        body: RefsBody {
            owner,
            slug,
            visibility,
            default_branch,
            branches,
            tags,
            viewer,
        },
    }
    .into_response()
}
