use anyhow::Result;
use axum::extract::{Path as AxumPath, State};
use axum::response::Response;

use crate::db::{self, Store};

use super::helpers::{
    error_response, friendly_date, friendly_status, list_projects_safe, render, render_markdown,
};
use super::project::views::TaskRow;
use super::AppState;

mod views;
use views::{BlockerRef, LogView, TaskTemplate, TaskView};

pub(in crate::cmd::webui) async fn task_handler(
    State(state): State<AppState>,
    AxumPath((name, id)): AxumPath<(String, String)>,
) -> Response {
    let root = state.data_root.clone();
    let result = tokio::task::spawn_blocking(move || -> Result<TaskTemplate> {
        let all_projects = list_projects_safe(&root);
        let store = Store::open(&root, &name)?;

        let task_id = db::resolve_task_id(&store, &id, false)?;
        let task = store
            .get_task(&task_id, false)?
            .ok_or_else(|| anyhow::anyhow!("task '{id}' not found"))?;

        // Partition blockers.
        let partition = db::partition_blockers(&store, &task.blockers)?;
        let blockers_open: Vec<BlockerRef> = partition
            .open
            .iter()
            .map(|b| BlockerRef {
                full_id: b.as_str().to_string(),
                short_id: b.short(),
            })
            .collect();
        let blockers_resolved: Vec<BlockerRef> = partition
            .resolved
            .iter()
            .map(|b| BlockerRef {
                full_id: b.as_str().to_string(),
                short_id: b.short(),
            })
            .collect();

        // Find subtasks.
        let all_tasks = store.list_tasks()?;
        let subtasks: Vec<TaskRow> = all_tasks
            .iter()
            .filter(|t| t.parent.as_ref() == Some(&task_id))
            .map(|t| {
                let status = t.status.as_str().to_string();
                TaskRow {
                    full_id: t.id.as_str().to_string(),
                    short_id: t.id.short(),
                    status_display: friendly_status(&status),
                    status,
                    task_type: t.task_type.clone(),
                    priority: t.priority.as_str().to_string(),
                    effort: t.effort.as_str().to_string(),
                    title: t.title.clone(),
                    labels: t.labels.clone(),
                    created_at_display: friendly_date(&t.created_at),
                    created_at: t.created_at.clone(),
                }
            })
            .collect();

        let task_view = TaskView {
            full_id: task.id.as_str().to_string(),
            short_id: task.id.short(),
            title: task.title.clone(),
            description: render_markdown(&task.description),
            description_raw: task.description.clone(),
            task_type: task.task_type.clone(),
            status: task.status.as_str().to_string(),
            priority: task.priority.as_str().to_string(),
            effort: task.effort.as_str().to_string(),
            created_at_display: friendly_date(&task.created_at),
            created_at: task.created_at.clone(),
            updated_at_display: friendly_date(&task.updated_at),
            updated_at: task.updated_at.clone(),
            parent_id: task.parent.as_ref().map(|p| p.short()).unwrap_or_default(),
            labels: task.labels.clone(),
            logs: task
                .logs
                .iter()
                .map(|l| LogView {
                    timestamp_display: friendly_date(&l.timestamp),
                    timestamp: l.timestamp.clone(),
                    message: render_markdown(&l.message),
                })
                .collect(),
        };

        let edit_heading = format!("Edit {}", task_view.short_id);
        let edit_form_action = format!(
            "/projects/{}/tasks/{}",
            store.project_name(),
            task_view.full_id
        );

        Ok(TaskTemplate {
            all_projects,
            active_project: Some(name),
            project_name: store.project_name().to_string(),
            task: task_view,
            blockers_open,
            blockers_resolved,
            subtasks,
            edit_heading,
            edit_form_action,
        })
    })
    .await;

    match result {
        Ok(Ok(tmpl)) => render(tmpl),
        Ok(Err(e)) => error_response(500, &format!("{e}"), &[]),
        Err(e) => error_response(500, &format!("join error: {e}"), &[]),
    }
}
