//! HTTP handlers for task API
use crate::core::shared::state::AppState;
use crate::tasks::task_api::{html_renderers, utils};
use crate::tasks::types::TaskResponse;
use axum::extract::{Path, State};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Json};
use axum::routing::{delete, get, post, put};
use axum::Router;
use diesel::prelude::*;
use log::{error, info, warn};
use std::sync::Arc;
use uuid::Uuid;

/// Handler for task creation
pub async fn handle_task_create(
    State(state): State<Arc<AppState>>,
    Json(payload): Json<crate::tasks::types::CreateTaskRequest>,
) -> Result<Json<TaskResponse>, StatusCode> {
    let task_engine = &state.task_engine;

    match task_engine.create_task(payload).await {
        Ok(task) => Ok(Json(task)),
        Err(e) => {
            error!("Failed to create task: {}", e);
            Err(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

/// Handler for task update
pub async fn handle_task_update(
    State(state): State<Arc<AppState>>,
    Path(id): Path<Uuid>,
    Json(payload): Json<crate::tasks::types::TaskUpdate>,
) -> Result<Json<TaskResponse>, StatusCode> {
    let task_engine = &state.task_engine;

    match task_engine.update_task(id, payload).await {
        Ok(task) => Ok(Json(task.into())),
        Err(e) => {
            error!("Failed to update task: {}", e);
            Err(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

/// Handler for task deletion
pub async fn handle_task_delete(
    State(state): State<Arc<AppState>>,
    Path(id): Path<Uuid>,
) -> Result<StatusCode, StatusCode> {
    let task_engine = &state.task_engine;

    match task_engine.delete_task(id).await {
        Ok(_) => Ok(StatusCode::NO_CONTENT),
        Err(e) => {
            error!("Failed to delete task: {}", e);
            Err(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

/// Handler for listing all tasks
pub async fn handle_task_list(
    State(state): State<Arc<AppState>>,
) -> impl IntoResponse {
    let conn = state.conn.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut db_conn = conn.get().map_err(|e| {
            error!("DB connection error: {}", e);
            diesel::result::Error::DatabaseError(
                diesel::result::DatabaseErrorKind::UnableToSendCommand,
                Box::new(e.to_string()),
            )
        })?;

        #[derive(Debug, QueryableByName, serde::Serialize)]
        struct AutoTaskRow {
            #[diesel(sql_type = diesel::sql_types::Uuid)]
            pub id: Uuid,
            #[diesel(sql_type = diesel::sql_types::Text)]
            pub title: String,
            #[diesel(sql_type = diesel::sql_types::Text)]
            pub status: String,
            #[diesel(sql_type = diesel::sql_types::Text)]
            pub priority: String,
            #[diesel(sql_type = diesel::sql_types::Double)]
            pub progress: f64,
        }

        let tasks = diesel::sql_query(
            "SELECT id, title, status, priority, progress FROM auto_tasks ORDER BY created_at DESC"
        )
        .load::<AutoTaskRow>(&mut db_conn)
        .map_err(|e| {
            error!("Query error: {}", e);
            e
        })?;

        Ok::<Vec<AutoTaskRow>, diesel::result::Error>(tasks)
    })
    .await;

    match result {
        Ok(Ok(tasks)) => (StatusCode::OK, axum::Json(tasks)).into_response(),
        Ok(Err(e)) => {
            error!("DB error: {}", e);
            (StatusCode::INTERNAL_SERVER_ERROR, "Database error").into_response()
        }
        Err(e) => {
            error!("Task join error: {}", e);
            (StatusCode::INTERNAL_SERVER_ERROR, "Internal server error").into_response()
        }
    }
}

/// Handler for getting a single task
pub async fn handle_task_get(
    State(state): State<Arc<AppState>>,
    Path(id): Path<String>,
    headers: axum::http::HeaderMap,
) -> impl IntoResponse {
    info!("*** Handler called for task: {} ***", id);

    // Check if client wants JSON (for polling) vs HTML (for HTMX)
    let wants_json = headers
        .get(axum::http::header::ACCEPT)
        .and_then(|v| v.to_str().ok())
        .map(|v| v.contains("application/json"))
        .unwrap_or(false);

    let conn = state.conn.clone();
    let task_id = id.clone();

    let result = tokio::task::spawn_blocking(move || {
        let mut db_conn = conn
            .get()
            .map_err(|e| {
                error!("DB connection error: {}", e);
                format!("DB connection error: {}", e)
            })?;

        #[derive(Debug, QueryableByName, serde::Serialize)]
        struct AutoTaskRow {
            #[diesel(sql_type = diesel::sql_types::Uuid)]
            pub id: Uuid,
            #[diesel(sql_type = diesel::sql_types::Text)]
            pub title: String,
            #[diesel(sql_type = diesel::sql_types::Text)]
            pub status: String,
            #[diesel(sql_type = diesel::sql_types::Text)]
            pub priority: String,
            #[diesel(sql_type = diesel::sql_types::Nullable<diesel::sql_types::Text>)]
            pub intent: Option<String>,
            #[diesel(sql_type = diesel::sql_types::Nullable<diesel::sql_types::Text>)]
            pub error: Option<String>,
            #[diesel(sql_type = diesel::sql_types::Double)]
            pub progress: f64,
            #[diesel(sql_type = diesel::sql_types::Integer)]
            pub current_step: i32,
            #[diesel(sql_type = diesel::sql_types::Integer)]
            pub total_steps: i32,
            #[diesel(sql_type = diesel::sql_types::Nullable<diesel::sql_types::Jsonb>)]
            pub step_results: Option<serde_json::Value>,
            #[diesel(sql_type = diesel::sql_types::Nullable<diesel::sql_types::Jsonb>)]
            pub manifest_json: Option<serde_json::Value>,
            #[diesel(sql_type = diesel::sql_types::Timestamptz)]
            pub created_at: chrono::DateTime<chrono::Utc>,
            #[diesel(sql_type = diesel::sql_types::Nullable<diesel::sql_types::Timestamptz>)]
            pub started_at: Option<chrono::DateTime<chrono::Utc>>,
            #[diesel(sql_type = diesel::sql_types::Nullable<diesel::sql_types::Timestamptz>)]
            pub completed_at: Option<chrono::DateTime<chrono::Utc>>,
        }

        let parsed_uuid = match Uuid::parse_str(&task_id) {
            Ok(u) => {
                info!("Parsed UUID: {}", u);
                u
            }
            Err(e) => {
                error!("Invalid task ID '{}': {}", task_id, e);
                return Err(format!("Invalid task ID: {}", task_id));
            }
        };

        let task: Option<AutoTaskRow> = diesel::sql_query(
            "SELECT id, title, status, priority, intent, error, progress, current_step, total_steps, step_results, manifest_json, created_at, started_at, completed_at
             FROM auto_tasks WHERE id = $1 LIMIT 1"
        )
        .bind::<diesel::sql_types::Uuid, _>(parsed_uuid)
        .get_result(&mut db_conn)
        .map_err(|e| {
            error!("Query error for {}: {}", parsed_uuid, e);
            e
        })
        .ok();

        info!("Query result for {}: found={}", parsed_uuid, task.is_some());
        Ok::<_, String>(task)
    })
    .await
    .unwrap_or_else(|e| {
        error!("Task query failed: {}", e);
        Err(format!("Task query failed: {}", e))
    });

    match result {
        Ok(Some(task)) => {
            info!("Returning task: {} - {} (wants_json={})", task.id, task.title, wants_json);

            // Return JSON for API polling clients
            if wants_json {
                return (
                    StatusCode::OK,
                    [(axum::http::header::CONTENT_TYPE, "application/json")],
                    serde_json::json!({
                        "id": task.id.to_string(),
                        "title": task.title,
                        "status": task.status,
                        "priority": task.priority,
                        "intent": task.intent,
                        "error": task.error,
                        "progress": (task.progress * 100.0) as u8,
                        "current_step": task.current_step,
                        "total_steps": task.total_steps,
                        "created_at": task.created_at.to_rfc3339(),
                        "started_at": task.started_at.map(|t| t.to_rfc3339()),
                        "completed_at": task.completed_at.map(|t| t.to_rfc3339())
                    }).to_string()
                ).into_response();
            }

            // Return HTML for HTMX
            let status_class = match task.status.as_str() {
                "completed" | "done" => "completed",
                "running" | "pending" => "running",
                "failed" | "error" => "error",
                _ => "pending"
            };

            let runtime = if let Some(started) = task.started_at {
                let end_time = task.completed_at.unwrap_or_else(chrono::Utc::now);
                let duration = end_time.signed_duration_since(started);
                let mins = duration.num_minutes();
                let secs = duration.num_seconds() % 60;
                if mins > 0 {
                    format!("{}m {}s", mins, secs)
                } else {
                    format!("{}s", secs)
                }
            } else {
                "Not started".to_string()
            };

            let task_id = task.id.to_string();
            let error_html = task.error.clone().map(|e| format!(
                r#"<div class="error-alert">
                    <span class="error-icon">⚠</span>
                    <span class="error-text">{}</span>
                </div>"#, e
            )).unwrap_or_default();

            let status_label = match task.status.as_str() {
                "completed" | "done" => "Completed",
                "running" => "Running",
                "pending" => "Pending",
                "failed" | "error" => "Failed",
                "paused" => "Paused",
                "waiting_approval" => "Awaiting Approval",
                _ => &task.status
            };

            // Build terminal output from recent activity
            let terminal_html = html_renderers::build_terminal_html(&task.step_results, &task.status);

            // Extract app_url from step_results if task is completed
            let app_url = if task.status == "completed" || task.status == "done" {
                utils::extract_app_url_from_results(&task.step_results, &task.title)
            } else {
                None
            };

            let app_button_html = app_url.map(|url| format!(
                r#"<a href="{}" target="_blank" class="btn-action-rich btn-open-app" rel="noopener noreferrer">
                    <span class="btn-icon">🚀</span> Open App
                </a>"#,
                url
            )).unwrap_or_default();

            let cancel_button_html = match task.status.as_str() {
                "completed" | "done" | "failed" | "error" => String::new(),
                _ => format!(
                    r#"<button class="btn-action-rich btn-cancel" onclick="cancelTask('{task_id}')">
                            <span class="btn-icon">✗</span> Cancel
                        </button>"#
                ),
            };

            let (status_html, progress_log_html) = html_renderers::build_taskmd_html(&state, &task_id, &task.title, &runtime, task.manifest_json.as_ref());

            let html = format!(r#"
                <div class="task-detail-rich" data-task-id="{task_id}">
                    <!-- Header - compact -->
                    <div class="taskmd-header">
                        <h1 class="taskmd-title">{title}</h1>
                        <span class="taskmd-status-badge status-{status_class}">{status_label}</span>
                    </div>

                    {error_html}

                    <!-- STATUS Section -->
                    <div class="taskmd-section taskmd-section-status">
                        <div class="taskmd-section-header">STATUS</div>
                        <div class="taskmd-status-content">
                            {status_html}
                        </div>
                    </div>

                    <!-- PROGRESS LOG Section -->
                    <div class="taskmd-section taskmd-section-progress">
                        <div class="taskmd-section-header">PROGRESS LOG</div>
                        <div class="taskmd-progress-content" id="progress-log-{task_id}">
                            {progress_log_html}
                        </div>
                    </div>

                    <!-- TERMINAL Section -->
                    <div class="taskmd-section taskmd-section-terminal taskmd-terminal">
                        <div class="taskmd-terminal-header">
                            <div class="taskmd-terminal-title">
                                <span class="terminal-dot {terminal_active}"></span>
                                <span>TERMINAL (LIVE AGENT ACTIVITY)</span>
                            </div>
                            <div class="taskmd-terminal-stats">
                                <span>Processed: <strong id="terminal-processed-{task_id}">{processed_count}</strong> items</span>
                                <span class="stat-sep">|</span>
                                <span>Speed: <strong>{processing_speed}</strong></span>
                                <span class="stat-sep">|</span>
                                <span>ETA: <strong id="terminal-eta-{task_id}">{eta_display}</strong></span>
                            </div>
                        </div>
                        <div class="taskmd-terminal-output" id="terminal-output-{task_id}">
                            {terminal_html}
                        </div>
                    </div>

                    <!-- Actions -->
                    <div class="taskmd-actions">
                        {app_button_html}
                        {cancel_button_html}
                    </div>
                </div>
            "#,
                task_id = task_id,
                title = task.title,
                status_class = status_class,
                status_label = status_label,
                error_html = error_html,
                status_html = status_html,
                progress_log_html = progress_log_html,
                terminal_active = if task.status == "running" { "active" } else { "" },
                terminal_html = terminal_html,
                app_button_html = app_button_html,
                cancel_button_html = cancel_button_html,
                processed_count = utils::get_manifest_processed_count(&state, &task_id),
                processing_speed = utils::get_manifest_speed(&state, &task_id),
                eta_display = utils::get_manifest_eta(&state, &task_id),
            );
            (StatusCode::OK, axum::response::Html(html)).into_response()
        }
        Ok(None) => {
            warn!("Task not found: {}", id);
            (StatusCode::NOT_FOUND, axum::response::Html("<div class='error'>Task not found</div>".to_string())).into_response()
        }
        Err(e) => {
            error!("Error fetching task {}: {}", id, e);
            (StatusCode::INTERNAL_SERVER_ERROR, axum::response::Html(format!("<div class='error'>{}</div>", e))).into_response()
        }
    }
}

/// Configure task routes for the Axum router
pub fn configure_task_routes() -> Router<Arc<AppState>> {
    Router::new()
        .route("/tasks", post(handle_task_create))
        .route("/tasks", get(handle_task_list))
        .route("/tasks/:id", get(handle_task_get))
        .route("/tasks/:id", put(handle_task_update))
        .route("/tasks/:id", delete(handle_task_delete))
}
