//! Component Registry - Download and cache Vue component source code from GitHub
//! 组件注册表 - 从 GitHub 下载并缓存 Vue 组件源码

use std::collections::HashMap;
use std::path::{Path, PathBuf};
use tracing::{debug, info};

/// 组件信息
#[derive(Debug, Clone, serde::Deserialize)]
pub struct ComponentInfo {
    pub name: String,
    pub library: String,
    pub source_url: String,
    pub category: Option<String>,
    pub props: Option<Vec<String>>,
}

/// 路径推断规则
#[derive(Debug, Clone, serde::Deserialize)]
pub struct InferenceRule {
    pub library: String,
    pub pattern: String,
    pub url_template: String,
    pub transform: String,
}

/// 组件注册表
pub struct ComponentRegistry {
    /// 组件映射表
    registry: HashMap<String, ComponentInfo>,
    
    /// 推断规则
    inference_rules: Vec<InferenceRule>,
    
    /// 本地缓存目录
    cache_dir: PathBuf,
    
    /// HTTP 客户端
    client: reqwest::blocking::Client,
}

impl ComponentRegistry {
    /// 创建新的组件注册表
    pub fn new(cache_dir: PathBuf) -> Result<Self, String> {
        // 确保缓存目录存在
        std::fs::create_dir_all(&cache_dir)
            .map_err(|e| format!("Failed to create cache directory: {}", e))?;
        
        info!(cache_dir = ?cache_dir, "ComponentRegistry initialized");
        
        Ok(Self {
            registry: HashMap::new(),
            inference_rules: Vec::new(),
            cache_dir,
            client: reqwest::blocking::Client::builder()
                .timeout(std::time::Duration::from_secs(30))
                .build()
                .map_err(|e| format!("Failed to create HTTP client: {}", e))?,
        })
    }
    
    /// 从 JSON 文件加载注册表
    pub fn load_from_file<P: AsRef<Path>>(&mut self, path: P) -> Result<(), String> {
        let content = std::fs::read_to_string(path)
            .map_err(|e| format!("Failed to read registry file: {}", e))?;
        
        let json: serde_json::Value = serde_json::from_str(&content)
            .map_err(|e| format!("Failed to parse registry JSON: {}", e))?;
        
        // 加载推断规则
        if let Some(rules) = json.get("inference_rules").and_then(|v| v.get("rules")) {
            self.inference_rules = serde_json::from_value(rules.clone())
                .map_err(|e| format!("Failed to parse inference rules: {}", e))?;
            debug!(rules_count = self.inference_rules.len(), "Loaded inference rules");
        }
        
        // 加载组件映射
        if let Some(libraries) = json.get("libraries") {
            for (lib_name, lib_data) in libraries.as_object().unwrap_or(&serde_json::Map::new()) {
                if let Some(components) = lib_data.get("components") {
                    for (comp_name, comp_data) in components.as_object().unwrap_or(&serde_json::Map::new()) {
                        if let Some(source_url) = comp_data.get("source_url").and_then(|v| v.as_str()) {
                            self.registry.insert(comp_name.clone(), ComponentInfo {
                                name: comp_name.clone(),
                                library: lib_name.clone(),
                                source_url: source_url.to_string(),
                                category: comp_data.get("category").and_then(|v| v.as_str()).map(|s| s.to_string()),
                                props: comp_data.get("props").and_then(|v| v.as_array()).map(|arr| {
                                    arr.iter().filter_map(|v| v.as_str()).map(|s| s.to_string()).collect()
                                }),
                            });
                        }
                    }
                }
            }
            debug!(components_count = self.registry.len(), "Loaded component registry");
        }
        
        Ok(())
    }
    
    /// 获取组件源码（优先缓存，否则下载）
    pub fn fetch_component_source(&mut self, component_name: &str) -> Result<String, String> {
        // 1. 检查缓存
        if let Some(cached) = self.get_cached_source(component_name) {
            debug!(component = component_name, "Using cached component source");
            return Ok(cached);
        }
        
        // 2. 从注册表查找 URL
        let source_url = if let Some(info) = self.registry.get(component_name) {
            info.source_url.clone()
        } else {
            // 3. 尝试推断 URL
            self.infer_source_url(component_name)
                .ok_or_else(|| format!("Component '{}' not found in registry and cannot be inferred", component_name))?
        };
        
        info!(component = component_name, url = &source_url, "Downloading component source");
        
        // 4. 下载源码
        let source = self.download_from_url(&source_url)?;
        
        // 5. 缓存到本地
        self.cache_component(component_name, &source)?;
        
        Ok(source)
    }
    
    /// 从 URL 下载内容
    fn download_from_url(&self, url: &str) -> Result<String, String> {
        debug!(url = url, "Downloading from URL");
        
        let response = self.client.get(url)
            .send()
            .map_err(|e| format!("HTTP request failed: {}", e))?;
        
        if !response.status().is_success() {
            return Err(format!("HTTP {} for URL: {}", response.status(), url));
        }
        
        let content = response.text()
            .map_err(|e| format!("Failed to read response: {}", e))?;
        
        debug!(content_len = content.len(), "Downloaded successfully");
        Ok(content)
    }
    
    /// 推断组件源码 URL
    fn infer_source_url(&self, component_name: &str) -> Option<String> {
        for rule in &self.inference_rules {
            // 简单的模式匹配（实际应使用 regex）
            if self.matches_pattern(component_name, &rule.pattern) {
                let transformed = self.transform_name(component_name, &rule.transform);
                let url = self.build_url(&rule.url_template, &transformed, component_name);
                debug!(component = component_name, library = &rule.library, url = &url, "Inferred URL");
                return Some(url);
            }
        }
        None
    }
    
    /// 模式匹配（简化版）
    fn matches_pattern(&self, name: &str, pattern: &str) -> bool {
        // 简化处理：检查前缀
        if pattern.starts_with("^El") && name.starts_with("El") {
            return true;
        }
        if pattern.starts_with("^N") && name.starts_with("N") && !name.starts_with("Na") {
            return true;
        }
        if pattern.starts_with("^Van") && name.starts_with("Van") {
            return true;
        }
        if pattern == "^[A-Z][a-zA-Z]+$" && !name.starts_with(|c: char| c.is_lowercase()) {
            // PrimeVue: 纯驼峰命名
            return !name.starts_with("El") && !name.starts_with("N") && !name.starts_with("Van") && !name.starts_with("V");
        }
        false
    }
    
    /// 名称转换
    fn transform_name(&self, name: &str, transform: &str) -> String {
        match transform {
            "pascal_to_kebab" => {
                // ElButton -> button
                let without_prefix = if name.starts_with("El") { &name[2..] } else { name };
                self.pascal_to_kebab(without_prefix)
            }
            "remove_prefix_n" => {
                // NButton -> Button
                if name.starts_with("N") {
                    name[1..].to_string()
                } else {
                    name.to_string()
                }
            }
            "remove_prefix_van" => {
                // VanButton -> Button
                if name.starts_with("Van") {
                    name[3..].to_string()
                } else {
                    name.to_string()
                }
            }
            _ => name.to_string(),
        }
    }
    
    /// PascalCase 转 kebab-case
    fn pascal_to_kebab(&self, name: &str) -> String {
        let mut result = String::new();
        for (i, c) in name.chars().enumerate() {
            if i > 0 && c.is_uppercase() {
                result.push('-');
            }
            result.push(c.to_lowercase().next().unwrap());
        }
        result
    }
    
    /// 构建 URL
    fn build_url(&self, template: &str, transformed: &str, original: &str) -> String {
        let lower_name = transformed.to_lowercase();
        template
            .replace("{kebab_name}", &self.pascal_to_kebab(transformed))
            .replace("{lower_name}", &lower_name)
            .replace("{PascalName}", transformed)
            .replace("{component_name}", original)
    }
    
    /// 获取缓存的源码
    fn get_cached_source(&self, component_name: &str) -> Option<String> {
        let cache_path = self.get_cache_path(component_name);
        if cache_path.exists() {
            std::fs::read_to_string(&cache_path).ok()
        } else {
            None
        }
    }
    
    /// 缓存组件源码
    fn cache_component(&self, component_name: &str, source: &str) -> Result<(), String> {
        let cache_path = self.get_cache_path(component_name);
        std::fs::write(&cache_path, source)
            .map_err(|e| format!("Failed to cache component: {}", e))?;
        debug!(component = component_name, path = ?cache_path, "Cached component source");
        Ok(())
    }
    
    /// 获取缓存文件路径
    fn get_cache_path(&self, component_name: &str) -> PathBuf {
        // 使用组件名作为文件名（转义特殊字符）
        let safe_name = component_name.replace(|c: char| !c.is_alphanumeric(), "_");
        self.cache_dir.join(format!("{}.vue", safe_name))
    }
}
