use leptos::prelude::*;
use serde::{Deserialize, Serialize};
use gloo_net::http::Request;

const API_BASE: &str = "http://localhost:8080/api/v1";

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuditLogEntry {
    pub event_id: String,
    pub timestamp: String,
    pub user: UserInfo,
    pub action: ActionInfo,
    pub result: ResultInfo,
    pub metadata: Option<serde_json::Value>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct UserInfo {
    pub id: String,
    pub name: String,
    pub ip: String,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ActionInfo {
    pub action_type: String,
    pub resource: String,
    pub workspace: String,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ResultInfo {
    pub status: String,
    pub duration_ms: u64,
    pub error: Option<String>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuditQueryParams {
    pub user_id: Option<String>,
    pub action_type: Option<String>,
    pub resource: Option<String>,
    pub workspace: Option<String>,
    pub status: Option<String>,
    pub date_from: Option<String>,
    pub date_to: Option<String>,
    pub limit: Option<u32>,
    pub offset: Option<u32>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuditQueryResponse {
    pub entries: Vec<AuditLogEntry>,
    pub total: u32,
    pub limit: u32,
    pub offset: u32,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuditStats {
    pub total_events: u64,
    pub success_rate: f64,
    pub avg_duration_ms: f64,
    pub events_by_action: Vec<ActionStat>,
    pub events_by_user: Vec<UserStat>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ActionStat {
    pub action_type: String,
    pub count: u64,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct UserStat {
    pub user_name: String,
    pub count: u64,
}

pub struct AuditService;

impl AuditService {
    pub fn new() -> Self {
        Self
    }

    /// Query audit logs with filters
    pub async fn query(
        &self,
        access_token: String,
        params: AuditQueryParams,
    ) -> Result<AuditQueryResponse, String> {
        let mut url = format!("{}/audit/logs", API_BASE);
        let mut query_parts = Vec::new();

        if let Some(user_id) = &params.user_id {
            query_parts.push(format!("user_id={}", user_id));
        }
        if let Some(action_type) = &params.action_type {
            query_parts.push(format!("action_type={}", action_type));
        }
        if let Some(resource) = &params.resource {
            query_parts.push(format!("resource={}", resource));
        }
        if let Some(workspace) = &params.workspace {
            query_parts.push(format!("workspace={}", workspace));
        }
        if let Some(status) = &params.status {
            query_parts.push(format!("status={}", status));
        }
        if let Some(date_from) = &params.date_from {
            query_parts.push(format!("date_from={}", date_from));
        }
        if let Some(date_to) = &params.date_to {
            query_parts.push(format!("date_to={}", date_to));
        }
        if let Some(limit) = params.limit {
            query_parts.push(format!("limit={}", limit));
        }
        if let Some(offset) = params.offset {
            query_parts.push(format!("offset={}", offset));
        }

        if !query_parts.is_empty() {
            url.push('?');
            url.push_str(&query_parts.join("&"));
        }

        let response = Request::get(&url)
            .header("Authorization", &format!("Bearer {}", access_token))
            .send()
            .await
            .map_err(|e| format!("Failed to query audit logs: {}", e))?;

        if !response.ok() {
            let error_text = response
                .text()
                .await
                .unwrap_or_else(|_| "Unknown error".to_string());
            return Err(format!("Query failed: {}", error_text));
        }

        response
            .json::<AuditQueryResponse>()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))
    }

    /// Get audit statistics
    pub async fn get_stats(&self, access_token: String) -> Result<AuditStats, String> {
        let response = Request::get(&format!("{}/audit/stats", API_BASE))
            .header("Authorization", &format!("Bearer {}", access_token))
            .send()
            .await
            .map_err(|e| format!("Failed to get stats: {}", e))?;

        if !response.ok() {
            let error_text = response
                .text()
                .await
                .unwrap_or_else(|_| "Unknown error".to_string());
            return Err(format!("Failed to get stats: {}", error_text));
        }

        response
            .json::<AuditStats>()
            .await
            .map_err(|e| format!("Failed to parse stats: {}", e))
    }

    /// Export audit logs
    pub async fn export(
        &self,
        access_token: String,
        format: &str,
        params: AuditQueryParams,
    ) -> Result<String, String> {
        let mut url = format!("{}/audit/export?format={}", API_BASE, format);

        if let Some(user_id) = &params.user_id {
            url.push_str(&format!("&user_id={}", user_id));
        }
        if let Some(action_type) = &params.action_type {
            url.push_str(&format!("&action_type={}", action_type));
        }
        if let Some(date_from) = &params.date_from {
            url.push_str(&format!("&date_from={}", date_from));
        }
        if let Some(date_to) = &params.date_to {
            url.push_str(&format!("&date_to={}", date_to));
        }

        let response = Request::get(&url)
            .header("Authorization", &format!("Bearer {}", access_token))
            .send()
            .await
            .map_err(|e| format!("Failed to export logs: {}", e))?;

        if !response.ok() {
            let error_text = response
                .text()
                .await
                .unwrap_or_else(|_| "Unknown error".to_string());
            return Err(format!("Export failed: {}", error_text));
        }

        response
            .text()
            .await
            .map_err(|e| format!("Failed to read export data: {}", e))
    }

    /// Get available action types
    pub async fn get_action_types(&self, access_token: String) -> Result<Vec<String>, String> {
        let response = Request::get(&format!("{}/audit/action-types", API_BASE))
            .header("Authorization", &format!("Bearer {}", access_token))
            .send()
            .await
            .map_err(|e| format!("Failed to get action types: {}", e))?;

        if !response.ok() {
            return Err("Failed to get action types".to_string());
        }

        response
            .json::<Vec<String>>()
            .await
            .map_err(|e| format!("Failed to parse action types: {}", e))
    }

    /// Get available workspaces
    pub async fn get_workspaces(&self, access_token: String) -> Result<Vec<String>, String> {
        let response = Request::get(&format!("{}/audit/workspaces", API_BASE))
            .header("Authorization", &format!("Bearer {}", access_token))
            .send()
            .await
            .map_err(|e| format!("Failed to get workspaces: {}", e))?;

        if !response.ok() {
            return Err("Failed to get workspaces".to_string());
        }

        response
            .json::<Vec<String>>()
            .await
            .map_err(|e| format!("Failed to parse workspaces: {}", e))
    }
}

impl Default for AuditService {
    fn default() -> Self {
        Self::new()
    }
}
