use askama::Template;

use super::helpers::SortField;

/// A project card on the root page — either healthy or failed.
pub(super) enum ProjectCard {
    Ok {
        name: String,
        open: usize,
        in_progress: usize,
        closed: usize,
        total: usize,
    },
    Err {
        name: String,
        error: String,
    },
}

/// Minimal view-model for a scored task in the "Next Up" table.
pub(super) struct ScoredEntry {
    pub(super) id: String,
    pub(super) short_id: String,
    pub(super) title: String,
    pub(super) score: String,
    pub(super) status: String,
    pub(super) status_display: &'static str,
}

/// Minimal view-model for a task row in the project task table.
pub(super) struct TaskRow {
    pub(super) full_id: String,
    pub(super) short_id: String,
    pub(super) status: String,
    pub(super) status_display: &'static str,
    pub(super) priority: String,
    pub(super) effort: String,
    pub(super) title: String,
    pub(super) created_at: String,
    pub(super) created_at_display: String,
}

/// View-model for the task detail page.
pub(super) struct TaskView {
    pub(super) full_id: String,
    pub(super) short_id: String,
    pub(super) title: String,
    pub(super) description: String,
    pub(super) task_type: String,
    pub(super) status: String,
    pub(super) priority: String,
    pub(super) effort: String,
    pub(super) created_at: String,
    pub(super) created_at_display: String,
    pub(super) updated_at: String,
    pub(super) updated_at_display: String,
    pub(super) labels: Vec<String>,
    pub(super) logs: Vec<LogView>,
}

pub(super) struct LogView {
    pub(super) timestamp: String,
    pub(super) timestamp_display: String,
    pub(super) message: String,
}

/// A blocker reference for the task detail page.
pub(super) struct BlockerRef {
    pub(super) full_id: String,
    pub(super) short_id: String,
}

/// Sort context passed to the task_table macro. When present, column headers
/// become clickable links that set sort/order query params.
pub(super) struct SortContext {
    /// Base URL for sort links (e.g. `/projects/myproj`).
    pub(super) base_href: String,
    /// Current sort field.
    pub(super) field: String,
    /// Current sort order ("asc" or "desc").
    pub(super) order: String,
    /// Query string fragment for the current filters (without sort/order/page),
    /// suitable for appending to hrefs.
    pub(super) filter_qs: String,
}

impl SortContext {
    /// Build the href for a column header link. Clicking the currently-active
    /// column toggles direction; clicking a different column uses its default.
    fn column_href(&self, col: &str) -> String {
        let order = if col == self.field {
            // Toggle current direction.
            match self.order.as_str() {
                "asc" => "desc",
                _ => "asc",
            }
        } else {
            // Use the column's sensible default.
            SortField::parse(col)
                .map(|f| f.default_order().as_str())
                .unwrap_or("asc")
        };
        let mut qs = self.filter_qs.clone();
        if !qs.is_empty() {
            qs.push('&');
        }
        qs.push_str(&format!("sort={col}&order={order}"));
        format!("{}?{qs}", self.base_href)
    }

    /// Return the arrow indicator for the active column, or empty string.
    fn arrow(&self, col: &str) -> &str {
        if col == self.field {
            match self.order.as_str() {
                "asc" => " ↑",
                "desc" => " ↓",
                _ => "",
            }
        } else {
            ""
        }
    }
}

#[derive(Template)]
#[template(path = "index.html")]
pub(super) struct IndexTemplate {
    pub(super) all_projects: Vec<String>,
    pub(super) active_project: Option<String>,
    pub(super) projects: Vec<ProjectCard>,
}

#[derive(Template)]
#[template(path = "project.html")]
pub(super) struct ProjectTemplate {
    pub(super) all_projects: Vec<String>,
    pub(super) active_project: Option<String>,
    pub(super) project_name: String,
    pub(super) stats_open: usize,
    pub(super) stats_in_progress: usize,
    pub(super) stats_closed: usize,
    pub(super) next_up: Vec<ScoredEntry>,
    pub(super) page_tasks: Vec<TaskRow>,
    pub(super) all_labels: Vec<String>,
    pub(super) filter_status: Option<String>,
    pub(super) filter_priority: Option<String>,
    pub(super) filter_effort: Option<String>,
    pub(super) filter_label: Option<String>,
    pub(super) filter_search: String,
    pub(super) page: usize,
    pub(super) total_pages: usize,
    pub(super) pagination_pages: Vec<usize>,
    pub(super) sort_ctx: SortContext,
}

impl ProjectTemplate {
    /// Build a query-string fragment containing the current filters (no sort,
    /// no page). Reused by both pagination and sort helpers.
    fn filter_qs(&self) -> String {
        let mut parts = Vec::new();
        if let Some(ref s) = self.filter_status {
            parts.push(format!("status={s}"));
        }
        if let Some(ref p) = self.filter_priority {
            parts.push(format!("priority={p}"));
        }
        if let Some(ref e) = self.filter_effort {
            parts.push(format!("effort={e}"));
        }
        if let Some(ref l) = self.filter_label {
            parts.push(format!("label={l}"));
        }
        if !self.filter_search.is_empty() {
            parts.push(format!("q={}", self.filter_search));
        }
        parts.join("&")
    }

    /// Build a pagination link preserving current filter and sort params.
    fn pagination_href(&self, target_page: &usize) -> String {
        let target_page = *target_page;
        let mut qs = self.filter_qs();
        if !qs.is_empty() {
            qs.push('&');
        }
        qs.push_str(&format!(
            "sort={}&order={}",
            self.sort_ctx.field, self.sort_ctx.order
        ));
        qs.push_str(&format!("&page={target_page}"));
        format!("/projects/{}?{qs}", self.project_name)
    }
}

#[derive(Template)]
#[template(path = "task.html")]
pub(super) struct TaskTemplate {
    pub(super) all_projects: Vec<String>,
    pub(super) active_project: Option<String>,
    pub(super) project_name: String,
    pub(super) task: TaskView,
    pub(super) blockers_open: Vec<BlockerRef>,
    pub(super) blockers_resolved: Vec<BlockerRef>,
    pub(super) subtasks: Vec<TaskRow>,
}

#[derive(Template)]
#[template(path = "error.html")]
pub(super) struct ErrorTemplate {
    pub(super) all_projects: Vec<String>,
    pub(super) active_project: Option<String>,
    pub(super) status_code: u16,
    pub(super) message: String,
}
