use actix_web::{HttpResponse, web};
use serde::{Deserialize, Serialize};

use crate::{
    http::{HttpAppState, utils::get_repo_model},
    sync::cicheck::poll_ci_task_for_repo,
};

#[derive(Debug, Deserialize)]
pub struct ActionQuery {
    #[serde(default = "default_timeout")]
    pub timeout: usize,
}

fn default_timeout() -> usize {
    5
}

#[derive(Debug, Serialize)]
struct ActionTask {
    id: String,
    repo_id: String,
    pipeline_name: String,
    trigger: String,
}

#[derive(Debug, Serialize)]
struct ActionResponse {
    status: String,
    task: Option<ActionTask>,
}
pub async fn action_poll(
    path: web::Path<(String, String)>,
    query: web::Query<ActionQuery>,
    state: web::Data<HttpAppState>,
) -> HttpResponse {
    let (namespace, repo_name) = path.into_inner();

    let repo_model =
        match get_repo_model(&namespace, &repo_name, &state.db).await {
            Ok(m) => m,
            Err(_) => {
                return HttpResponse::NotFound().json(ActionResponse {
                    status: "not_found".into(),
                    task: None,
                });
            }
        };

    let task_json =
        poll_ci_task_for_repo(&state.sync.pool(), repo_model.id, query.timeout)
            .await;

    match task_json {
        Some(json) => {
            let hook_task: serde_json::Value = match serde_json::from_str(&json)
            {
                Ok(v) => v,
                Err(_) => {
                    return HttpResponse::InternalServerError().json(
                        ActionResponse {
                            status: "error".into(),
                            task: None,
                        },
                    );
                }
            };

            let task_id = hook_task
                .get("id")
                .and_then(|v| v.as_str())
                .unwrap_or("")
                .to_string();

            let pipeline_name = hook_task
                .get("payload")
                .and_then(|p| p.get("pipeline_name"))
                .and_then(|v| v.as_str())
                .unwrap_or("")
                .to_string();

            let trigger = hook_task
                .get("payload")
                .and_then(|p| p.get("trigger"))
                .and_then(|v| v.as_str())
                .unwrap_or("")
                .to_string();

            HttpResponse::Ok().json(ActionResponse {
                status: "pending".into(),
                task: Some(ActionTask {
                    id: task_id,
                    repo_id: repo_model.id.to_string(),
                    pipeline_name,
                    trigger,
                }),
            })
        }
        None => HttpResponse::NoContent().finish(),
    }
}
