use crate::error::{ComfyUIError, Result};
use crate::models::*;
use crate::types::*;
use reqwest::{Client, Response};
use serde_json::Value;
use url::Url;

/// UniComfyUI API client
#[derive(Debug, Clone)]
pub struct UniComfyUIClient {
    client: Client,
    base_url: Url,
}

impl UniComfyUIClient {
    /// Create a new UniComfyUI client
    pub fn new(base_url: &str) -> Result<Self> {
        let base_url = Url::parse(base_url)?;
        let client = Client::new();

        Ok(Self { client, base_url })
    }

    /// Create a new UniComfyUI client with custom reqwest client
    pub fn with_client(base_url: &str, client: Client) -> Result<Self> {
        let base_url = Url::parse(base_url)?;

        Ok(Self { client, base_url })
    }

    /// Build URL for an endpoint
    fn build_url(&self, path: &str) -> Result<Url> {
        Ok(self.base_url.join(path)?)
    }

    /// Handle HTTP response and convert to appropriate result
    async fn handle_response<T>(&self, response: Response) -> Result<T>
    where
        T: serde::de::DeserializeOwned,
    {
        let status = response.status();
        
        if status.is_success() {
            let text = response.text().await?;
            if text.is_empty() {
                // Handle empty responses for some endpoints
                return Ok(serde_json::from_value(Value::Null)?);
            }
            Ok(serde_json::from_str(&text)?)
        } else {
            let error_text = response.text().await.unwrap_or_default();
            Err(ComfyUIError::Api {
                status: status.as_u16(),
                message: error_text,
            })
        }
    }

    // Status endpoints

    /// Get metrics - 获取队列状态概览
    pub async fn get_metrics(&self) -> Result<GenericResponse> {
        let url = self.build_url("/api/service/metrics")?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    /// Get servers status - 获取所有已配置的ComfyUI服务器的配置信息和实时状态
    pub async fn get_servers_status(&self) -> Result<Vec<ServerStatus>> {
        let url = self.build_url("/api/service/servers_status")?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    /// List server files - 获取指定ComfyUI服务器的输入和输出文件夹中的文件列表
    pub async fn list_server_files(&self, server_index: u32) -> Result<ServerFiles> {
        let url = self.build_url(&format!("/api/service/servers/{}/files", server_index))?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    // Workflow endpoints

    /// Get all workflows - 获取所有工作流
    pub async fn get_all_workflows(&self) -> Result<ObjectArrayResponse> {
        let url = self.build_url("/api/workflow")?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    /// Publish workflow - 发布工作流
    pub async fn publish_workflow(&self, data: JsonObject) -> Result<GenericResponse> {
        let url = self.build_url("/api/workflow")?;
        let response = self.client.post(url).json(&data).send().await?;
        self.handle_response(response).await
    }

    /// Delete workflow - 删除工作流
    pub async fn delete_workflow(&self, workflow_name: &str) -> Result<GenericResponse> {
        let url = self.build_url(&format!("/api/workflow/{}", workflow_name))?;
        let response = self.client.delete(url).send().await?;
        self.handle_response(response).await
    }

    /// Get one workflow - 获取工作流规范
    pub async fn get_one_workflow(
        &self,
        base_name: &str,
        version: Option<&str>,
    ) -> Result<GenericResponse> {
        let mut url = self.build_url(&format!("/api/workflow/{}", base_name))?;
        
        if let Some(version) = version {
            url.query_pairs_mut().append_pair("version", version);
        }
        
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    // Run endpoints

    /// Run workflow - 异步执行工作流
    pub async fn run_workflow(
        &self,
        workflow_name: &str,
        workflow_version: Option<&str>,
        data: JsonObject,
    ) -> Result<GenericResponse> {
        let mut url = self.build_url("/api/run")?;
        url.query_pairs_mut().append_pair("workflow_name", workflow_name);
        
        if let Some(version) = workflow_version {
            url.query_pairs_mut().append_pair("workflow_version", version);
        }
        
        let response = self.client.post(url).json(&data).send().await?;
        self.handle_response(response).await
    }

    /// Get run status - 获取工作流执行状态
    pub async fn get_run_status(&self, workflow_run_id: &str) -> Result<GenericResponse> {
        let url = self.build_url(&format!("/api/run/{}", workflow_run_id))?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    // RunX endpoints

    /// Model with multi dress - 一个模特，穿多件不同的衣服
    pub async fn model_with_multi_dress(
        &self,
        workflow_version: Option<&str>,
        data: JsonObject,
    ) -> Result<GenericResponse> {
        let mut url = self.build_url("/api/runx/model_with_multi_dress")?;

        if let Some(version) = workflow_version {
            url.query_pairs_mut().append_pair("workflow_version", version);
        }

        let response = self.client.post(url).json(&data).send().await?;
        self.handle_response(response).await
    }

    /// Get model with multi dress JSON schema - 获取工作流定义
    pub async fn model_with_multi_dress_json_schema(&self) -> Result<GenericResponse> {
        let url = self.build_url("/api/runx/model_with_multi_dress/json_schema")?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    // Monitor endpoints

    /// Monitor dashboard - 监控仪表板页面
    pub async fn monitor_dashboard(&self) -> Result<String> {
        let url = self.build_url("/monitor/")?;
        let response = self.client.get(url).send().await?;

        let status = response.status();
        if status.is_success() {
            Ok(response.text().await?)
        } else {
            let error_text = response.text().await.unwrap_or_default();
            Err(ComfyUIError::Api {
                status: status.as_u16(),
                message: error_text,
            })
        }
    }

    /// Get system stats - 获取系统统计信息
    pub async fn get_system_stats(&self) -> Result<AdditionalPropertiesResponse> {
        let url = self.build_url("/monitor/system-stats")?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    /// Get task stats - 获取任务统计信息
    pub async fn get_task_stats(&self) -> Result<AdditionalPropertiesResponse> {
        let url = self.build_url("/monitor/task-stats")?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    /// Get server status (monitor) - 获取服务器状态信息
    pub async fn get_monitor_server_status(&self) -> Result<ObjectArrayResponse> {
        let url = self.build_url("/monitor/server-status")?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    /// Get recent tasks - 获取最近的任务列表
    pub async fn get_recent_tasks(&self, limit: Option<i32>) -> Result<ObjectArrayResponse> {
        let mut url = self.build_url("/monitor/recent-tasks")?;

        if let Some(limit) = limit {
            url.query_pairs_mut().append_pair("limit", &limit.to_string());
        }

        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    /// Health check - 健康检查端点
    pub async fn health_check(&self) -> Result<AdditionalPropertiesResponse> {
        let url = self.build_url("/monitor/health")?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    // ComfyUI Server Management endpoints

    /// Register server - 注册ComfyUI服务器
    pub async fn register_server(
        &self,
        request: ServerRegistrationRequest,
    ) -> Result<StringDictResponse> {
        let url = self.build_url("/api/comfy/register")?;
        let response = self.client.post(url).json(&request).send().await?;
        self.handle_response(response).await
    }

    /// Update heartbeat - 更新服务器心跳
    pub async fn update_heartbeat(
        &self,
        request: ServerHeartbeatRequest,
    ) -> Result<StringDictResponse> {
        let url = self.build_url("/api/comfy/heartbeat")?;
        let response = self.client.post(url).json(&request).send().await?;
        self.handle_response(response).await
    }

    /// Unregister server - 注销ComfyUI服务器
    pub async fn unregister_server(
        &self,
        request: ServerUnregisterRequest,
    ) -> Result<StringDictResponse> {
        let url = self.build_url("/api/comfy/unregister")?;
        let response = self.client.post(url).json(&request).send().await?;
        self.handle_response(response).await
    }

    /// Get server status - 获取指定服务器状态
    pub async fn get_server_status(&self, server_name: &str) -> Result<ServerStatusResponse> {
        let url = self.build_url(&format!("/api/comfy/status/{}", server_name))?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    /// List all servers - 获取所有服务器列表
    pub async fn list_all_servers(&self) -> Result<Vec<ServerStatusResponse>> {
        let url = self.build_url("/api/comfy/list")?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    /// Get system health - 获取系统整体健康状态
    pub async fn get_system_health(&self) -> Result<AdditionalPropertiesResponse> {
        let url = self.build_url("/api/comfy/health")?;
        let response = self.client.get(url).send().await?;
        self.handle_response(response).await
    }

    /// Force health check - 强制执行健康检查
    pub async fn force_health_check(&self) -> Result<StringDictResponse> {
        let url = self.build_url("/api/comfy/force_health_check")?;
        let response = self.client.post(url).send().await?;
        self.handle_response(response).await
    }
}
