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

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorkflowTask {
    pub id: String,
    pub name: String,
    pub command: String,
    pub args: Vec<String>,
    pub dependencies: Vec<String>,
    pub status: TaskStatus,
    pub created_at: String,
    pub started_at: Option<String>,
    pub completed_at: Option<String>,
    pub output: Option<String>,
    pub error: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum TaskStatus {
    Pending,
    Running,
    Completed,
    Failed,
    Cancelled,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateServerWorkflow {
    pub infra: String,
    pub settings: String,
    pub servers: Vec<String>,
    pub check_mode: bool,
    pub wait: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TaskservWorkflow {
    pub infra: String,
    pub settings: String,
    pub taskserv: String,
    pub operation: String, // create, delete, generate, check-updates
    pub check_mode: bool,
    pub wait: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClusterWorkflow {
    pub infra: String,
    pub settings: String,
    pub cluster_type: String,
    pub operation: String, // create, delete
    pub check_mode: bool,
    pub wait: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchWorkflowRequest {
    pub workflow: BatchWorkflow,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchWorkflow {
    pub name: String,
    pub version: String,
    pub storage_backend: String,
    pub parallel_limit: u32,
    pub rollback_enabled: bool,
    pub operations: Vec<BatchOperation>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchOperation {
    pub id: String,
    pub operation_type: String,
    pub provider: String,
    pub dependencies: Vec<String>,
    pub server_configs: Option<Vec<ServerConfig>>,
    pub taskservs: Option<Vec<String>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ServerConfig {
    pub name: String,
    pub plan: String,
    pub zone: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Infrastructure {
    pub id: String,
    pub name: String,
    pub provider: String,
    pub status: String,
    pub servers: Vec<Server>,
    pub created_at: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Server {
    pub id: String,
    pub name: String,
    pub status: String,
    pub ip_address: Option<String>,
    pub plan: String,
    pub zone: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProviderCredentials {
    pub provider: String,
    pub credentials: HashMap<String, String>,
    pub encrypted: bool,
    pub last_used: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiResponse<T> {
    pub success: bool,
    pub data: Option<T>,
    pub error: Option<String>,
}

pub struct OrchestratorClient {
    base_url: String,
}

impl OrchestratorClient {
    pub fn new(base_url: String) -> Self {
        Self { base_url }
    }

    // Workflow Management
    pub async fn create_server_workflow(&self, workflow: CreateServerWorkflow) -> Result<String, String> {
        let url = format!("{}/workflows/servers/create", self.base_url);

        let response = Request::post(&url)
            .json(&workflow)
            .map_err(|e| format!("Request creation failed: {}", e))?
            .send()
            .await
            .map_err(|e| format!("Request failed: {}", e))?;

        let api_response: ApiResponse<String> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No task ID returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Unknown error".to_string()))
        }
    }

    pub async fn create_taskserv_workflow(&self, workflow: TaskservWorkflow) -> Result<String, String> {
        let url = format!("{}/workflows/taskserv/create", self.base_url);

        let response = Request::post(&url)
            .json(&workflow)
            .map_err(|e| format!("Request creation failed: {}", e))?
            .send()
            .await
            .map_err(|e| format!("Request failed: {}", e))?;

        let api_response: ApiResponse<String> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No task ID returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Unknown error".to_string()))
        }
    }

    pub async fn create_cluster_workflow(&self, workflow: ClusterWorkflow) -> Result<String, String> {
        let url = format!("{}/workflows/cluster/create", self.base_url);

        let response = Request::post(&url)
            .json(&workflow)
            .map_err(|e| format!("Request creation failed: {}", e))?
            .send()
            .await
            .map_err(|e| format!("Request failed: {}", e))?;

        let api_response: ApiResponse<String> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No task ID returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Unknown error".to_string()))
        }
    }

    // Batch Workflows
    pub async fn submit_batch_workflow(&self, request: BatchWorkflowRequest) -> Result<String, String> {
        let url = format!("{}/workflows/batch/submit", self.base_url);

        let response = Request::post(&url)
            .json(&request)
            .map_err(|e| format!("Request creation failed: {}", e))?
            .send()
            .await
            .map_err(|e| format!("Request failed: {}", e))?;

        let api_response: ApiResponse<String> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No batch ID returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Unknown error".to_string()))
        }
    }

    pub async fn get_batch_status(&self, batch_id: &str) -> Result<serde_json::Value, String> {
        let url = format!("{}/workflows/batch/{}", self.base_url, batch_id);

        let response = Request::get(&url)
            .send()
            .await
            .map_err(|e| format!("Request failed: {}", e))?;

        let api_response: ApiResponse<serde_json::Value> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No status data returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Unknown error".to_string()))
        }
    }

    // Task Management
    pub async fn get_task_status(&self, task_id: &str) -> Result<WorkflowTask, String> {
        let url = format!("{}/tasks/{}", self.base_url, task_id);

        let response = Request::get(&url)
            .send()
            .await
            .map_err(|e| format!("Request failed: {}", e))?;

        let api_response: ApiResponse<WorkflowTask> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No task data returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Unknown error".to_string()))
        }
    }

    pub async fn list_tasks(&self) -> Result<Vec<WorkflowTask>, String> {
        let url = format!("{}/tasks", self.base_url);

        let response = Request::get(&url)
            .send()
            .await
            .map_err(|e| format!("Request failed: {}", e))?;

        let api_response: ApiResponse<Vec<WorkflowTask>> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No tasks data returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Unknown error".to_string()))
        }
    }

    // Health Check
    pub async fn health_check(&self) -> Result<String, String> {
        let url = format!("{}/health", self.base_url);

        let response = Request::get(&url)
            .send()
            .await
            .map_err(|e| format!("Health check failed: {}", e))?;

        let api_response: ApiResponse<String> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse health response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No health data returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Health check failed".to_string()))
        }
    }

    // Rollback Operations
    pub async fn create_checkpoint(&self, name: String, description: Option<String>) -> Result<String, String> {
        let url = format!("{}/rollback/checkpoints", self.base_url);

        let request_body = serde_json::json!({
            "name": name,
            "description": description
        });

        let response = Request::post(&url)
            .json(&request_body)
            .map_err(|e| format!("Request creation failed: {}", e))?
            .send()
            .await
            .map_err(|e| format!("Request failed: {}", e))?;

        let api_response: ApiResponse<String> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No checkpoint ID returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Unknown error".to_string()))
        }
    }

    pub async fn execute_rollback(&self, checkpoint_id: Option<String>, operation_ids: Option<Vec<String>>) -> Result<serde_json::Value, String> {
        let url = format!("{}/rollback/execute", self.base_url);

        let request_body = serde_json::json!({
            "checkpoint_id": checkpoint_id,
            "operation_ids": operation_ids
        });

        let response = Request::post(&url)
            .json(&request_body)
            .map_err(|e| format!("Request creation failed: {}", e))?
            .send()
            .await
            .map_err(|e| format!("Request failed: {}", e))?;

        let api_response: ApiResponse<serde_json::Value> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No rollback result returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Unknown error".to_string()))
        }
    }

    // System Metrics
    pub async fn get_system_metrics(&self) -> Result<serde_json::Value, String> {
        let url = format!("{}/state/system/metrics", self.base_url);

        let response = Request::get(&url)
            .send()
            .await
            .map_err(|e| format!("Request failed: {}", e))?;

        let api_response: ApiResponse<serde_json::Value> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No metrics data returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Unknown error".to_string()))
        }
    }

    pub async fn get_system_health(&self) -> Result<serde_json::Value, String> {
        let url = format!("{}/state/system/health", self.base_url);

        let response = Request::get(&url)
            .send()
            .await
            .map_err(|e| format!("Request failed: {}", e))?;

        let api_response: ApiResponse<serde_json::Value> = response
            .json()
            .await
            .map_err(|e| format!("Failed to parse response: {}", e))?;

        if api_response.success {
            api_response.data.ok_or_else(|| "No health data returned".to_string())
        } else {
            Err(api_response.error.unwrap_or_else(|| "Unknown error".to_string()))
        }
    }
}

// Global client instance
thread_local! {
    static ORCHESTRATOR_CLIENT: OrchestratorClient = OrchestratorClient::new("http://localhost:8080".to_string());
}

pub fn get_orchestrator_client() -> &'static OrchestratorClient {
    ORCHESTRATOR_CLIENT.with(|client| {
        // This is a workaround for thread_local limitation
        // In a real app, you might want to use a different approach
        unsafe { &*(client as *const OrchestratorClient) }
    })
}

// Reactive hooks for Leptos components
pub fn use_task_status(task_id: String) -> (ReadSignal<Option<WorkflowTask>>, ReadSignal<bool>, Action<(), ()>) {
    let (task, set_task) = signal(None::<WorkflowTask>);
    let (loading, set_loading) = signal(false);

    let refresh_action = create_action(move |_: &()| {
        let task_id = task_id.clone();
        async move {
            set_loading.set(true);
            match get_orchestrator_client().get_task_status(&task_id).await {
                Ok(task_data) => {
                    set_task.set(Some(task_data));
                }
                Err(err) => {
                    logging::log!("Failed to fetch task status: {}", err);
                }
            }
            set_loading.set(false);
        }
    });

    // Auto-refresh every 5 seconds for running tasks
    Effect::new(move |_| {
        if let Some(t) = task.get() {
            if matches!(t.status, TaskStatus::Pending | TaskStatus::Running) {
                set_timeout(move || refresh_action.dispatch(()), std::time::Duration::from_secs(5));
            }
        }
    });

    (task, loading, refresh_action)
}

pub fn use_tasks_list() -> (ReadSignal<Vec<WorkflowTask>>, ReadSignal<bool>, Action<(), ()>) {
    let (tasks, set_tasks) = signal(Vec::<WorkflowTask>::new());
    let (loading, set_loading) = signal(false);

    let refresh_action = create_action(move |_: &()| {
        async move {
            set_loading.set(true);
            match get_orchestrator_client().list_tasks().await {
                Ok(tasks_data) => {
                    set_tasks.set(tasks_data);
                }
                Err(err) => {
                    logging::log!("Failed to fetch tasks: {}", err);
                }
            }
            set_loading.set(false);
        }
    });

    // Initial load
    refresh_action.dispatch(());

    (tasks, loading, refresh_action)
}

pub fn use_system_health() -> (ReadSignal<Option<serde_json::Value>>, ReadSignal<bool>, Action<(), ()>) {
    let (health, set_health) = signal(None::<serde_json::Value>);
    let (loading, set_loading) = signal(false);

    let refresh_action = create_action(move |_: &()| {
        async move {
            set_loading.set(true);
            match get_orchestrator_client().get_system_health().await {
                Ok(health_data) => {
                    set_health.set(Some(health_data));
                }
                Err(err) => {
                    logging::log!("Failed to fetch system health: {}", err);
                }
            }
            set_loading.set(false);
        }
    });

    // Auto-refresh every 30 seconds
    Effect::new(move |_| {
        set_timeout(move || refresh_action.dispatch(()), std::time::Duration::from_secs(30));
    });

    // Initial load
    refresh_action.dispatch(());

    (health, loading, refresh_action)
}
