// Tasks API endpoints

use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    response::IntoResponse,
    Json,
};
use serde::Deserialize;
use vapora_shared::models::{Task, TaskPriority, TaskStatus};

use crate::api::state::AppState;
use crate::api::ApiResult;

#[derive(Debug, Deserialize)]
pub struct TaskQueryParams {
    pub project_id: String,
    pub status: Option<String>,
    pub assignee: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct ReorderTaskPayload {
    pub task_order: i32,
    pub status: Option<TaskStatus>,
}

#[derive(Debug, Deserialize)]
pub struct AssignTaskPayload {
    pub assignee: String,
}

#[derive(Debug, Deserialize)]
pub struct UpdatePriorityPayload {
    pub priority: TaskPriority,
}

/// List tasks with optional filters
///
/// GET /api/v1/tasks?project_id=xxx&status=todo&assignee=agent1
pub async fn list_tasks(
    State(state): State<AppState>,
    Query(params): Query<TaskQueryParams>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let tasks = if let Some(status_str) = params.status {
        // Parse status
        let status: TaskStatus = serde_json::from_value(serde_json::json!(status_str))?;
        state
            .task_service
            .list_tasks_by_status(&params.project_id, tenant_id, status)
            .await?
    } else if let Some(assignee) = params.assignee {
        state
            .task_service
            .list_tasks_by_assignee(&params.project_id, tenant_id, &assignee)
            .await?
    } else {
        state
            .task_service
            .list_tasks(&params.project_id, tenant_id)
            .await?
    };

    Ok(Json(tasks))
}

/// Get a specific task
///
/// GET /api/v1/tasks/:id
pub async fn get_task(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let task = state.task_service.get_task(&id, tenant_id).await?;
    Ok(Json(task))
}

/// Create a new task
///
/// POST /api/v1/tasks
pub async fn create_task(
    State(state): State<AppState>,
    Json(mut task): Json<Task>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    task.tenant_id = "default".to_string();

    let created = state.task_service.create_task(task).await?;
    Ok((StatusCode::CREATED, Json(created)))
}

/// Update a task
///
/// PUT /api/v1/tasks/:id
pub async fn update_task(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(updates): Json<Task>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let updated = state
        .task_service
        .update_task(&id, tenant_id, updates)
        .await?;
    Ok(Json(updated))
}

/// Delete a task
///
/// DELETE /api/v1/tasks/:id
pub async fn delete_task(
    State(state): State<AppState>,
    Path(id): Path<String>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    state.task_service.delete_task(&id, tenant_id).await?;
    Ok(StatusCode::NO_CONTENT)
}

/// Reorder a task (for Kanban drag & drop)
///
/// PUT /api/v1/tasks/:id/reorder
pub async fn reorder_task(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(payload): Json<ReorderTaskPayload>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let updated = state
        .task_service
        .reorder_task(&id, tenant_id, payload.task_order, payload.status)
        .await?;
    Ok(Json(updated))
}

/// Update task status
///
/// PUT /api/v1/tasks/:id/status
pub async fn update_task_status(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(payload): Json<serde_json::Value>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let status: TaskStatus = serde_json::from_value(payload["status"].clone())?;

    let updated = state
        .task_service
        .update_task_status(&id, tenant_id, status)
        .await?;
    Ok(Json(updated))
}

/// Assign a task to an agent/user
///
/// PUT /api/v1/tasks/:id/assign
pub async fn assign_task(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(payload): Json<AssignTaskPayload>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let updated = state
        .task_service
        .assign_task(&id, tenant_id, payload.assignee)
        .await?;
    Ok(Json(updated))
}

/// Update task priority
///
/// PUT /api/v1/tasks/:id/priority
pub async fn update_priority(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(payload): Json<UpdatePriorityPayload>,
) -> ApiResult<impl IntoResponse> {
    // TODO: Extract tenant_id from JWT token
    let tenant_id = "default";

    let updated = state
        .task_service
        .update_priority(&id, tenant_id, payload.priority)
        .await?;
    Ok(Json(updated))
}
