use dioxus::prelude::*;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DastTargetsResponse {
    pub data: Vec<serde_json::Value>,
    pub total: Option<u64>,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DastScanRunsResponse {
    pub data: Vec<serde_json::Value>,
    pub total: Option<u64>,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DastFindingsResponse {
    pub data: Vec<serde_json::Value>,
    pub total: Option<u64>,
}

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DastFindingDetailResponse {
    pub data: serde_json::Value,
}

#[server]
pub async fn fetch_dast_targets() -> Result<DastTargetsResponse, ServerFnError> {
    let state: super::server_state::ServerState =
        dioxus_fullstack::FullstackContext::extract().await?;
    let url = format!("{}/api/v1/dast/targets", state.agent_api_url);
    let resp = reqwest::get(&url)
        .await
        .map_err(|e| ServerFnError::new(e.to_string()))?;
    let body: DastTargetsResponse = resp
        .json()
        .await
        .map_err(|e| ServerFnError::new(e.to_string()))?;
    Ok(body)
}

#[server]
pub async fn fetch_dast_scan_runs() -> Result<DastScanRunsResponse, ServerFnError> {
    let state: super::server_state::ServerState =
        dioxus_fullstack::FullstackContext::extract().await?;
    let url = format!("{}/api/v1/dast/scan-runs", state.agent_api_url);
    let resp = reqwest::get(&url)
        .await
        .map_err(|e| ServerFnError::new(e.to_string()))?;
    let body: DastScanRunsResponse = resp
        .json()
        .await
        .map_err(|e| ServerFnError::new(e.to_string()))?;
    Ok(body)
}

#[server]
pub async fn fetch_dast_findings() -> Result<DastFindingsResponse, ServerFnError> {
    let state: super::server_state::ServerState =
        dioxus_fullstack::FullstackContext::extract().await?;
    let url = format!("{}/api/v1/dast/findings", state.agent_api_url);
    let resp = reqwest::get(&url)
        .await
        .map_err(|e| ServerFnError::new(e.to_string()))?;
    let body: DastFindingsResponse = resp
        .json()
        .await
        .map_err(|e| ServerFnError::new(e.to_string()))?;
    Ok(body)
}

#[server]
pub async fn fetch_dast_finding_detail(
    id: String,
) -> Result<DastFindingDetailResponse, ServerFnError> {
    let state: super::server_state::ServerState =
        dioxus_fullstack::FullstackContext::extract().await?;
    let url = format!("{}/api/v1/dast/findings/{id}", state.agent_api_url);
    let resp = reqwest::get(&url)
        .await
        .map_err(|e| ServerFnError::new(e.to_string()))?;
    let body: DastFindingDetailResponse = resp
        .json()
        .await
        .map_err(|e| ServerFnError::new(e.to_string()))?;
    Ok(body)
}

#[server]
pub async fn add_dast_target(name: String, base_url: String) -> Result<(), ServerFnError> {
    let state: super::server_state::ServerState =
        dioxus_fullstack::FullstackContext::extract().await?;
    let url = format!("{}/api/v1/dast/targets", state.agent_api_url);
    let client = reqwest::Client::new();
    client
        .post(&url)
        .json(&serde_json::json!({
            "name": name,
            "base_url": base_url,
        }))
        .send()
        .await
        .map_err(|e| ServerFnError::new(e.to_string()))?;
    Ok(())
}

#[server]
pub async fn trigger_dast_scan(target_id: String) -> Result<(), ServerFnError> {
    let state: super::server_state::ServerState =
        dioxus_fullstack::FullstackContext::extract().await?;
    let url = format!(
        "{}/api/v1/dast/targets/{target_id}/scan",
        state.agent_api_url
    );
    let client = reqwest::Client::new();
    client
        .post(&url)
        .send()
        .await
        .map_err(|e| ServerFnError::new(e.to_string()))?;
    Ok(())
}
