//! Vue Component Loader - Load and parse Vue SFC with component imports
//! Vue 组件加载器 - 加载和解析包含组件导入的 Vue SFC
//!
//! 支持三种 import 来源：
//! 1. 本地源码（./path/to/Comp.vue）— 从文件系统读取
//! 2. 开源组件（'element-plus', 'naive-ui' 等）— 从 CDN 自动下载
//! 3. 未知来源 — 标记为未解析，提示用户输入源码位置

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

/// 导入类型
#[derive(Debug, Clone, PartialEq)]
pub enum ImportType {
    /// 本地相对路径/绝对路径导入: `import X from './Comp.vue'`
    Local,
    /// npm 包名导入: `import X from 'element-plus'`
    Package,
    /// scoped npm 包名: `import X from '@scope/package'`
    ScopedPackage,
    /// URL 导入: `import X from 'https://cdn.example.com/comp.vue'`
    Url,
    /// 具名导入: `import { X } from 'package'`
    Named { package_name: String },
}

/// 解析后的导入信息
#[derive(Debug, Clone)]
pub struct ImportInfo {
    /// 组件名称（用于模板中匹配标签）
    pub component_name: String,
    /// 原始导入路径（如 `'./Comp.vue'`, `'element-plus'` 等）
    pub raw_import: String,
    /// 导入类型
    pub import_type: ImportType,
    /// 解析后的路径（本地文件路径 / npm 包名 / URL）
    pub resolved_path: PathBuf,
}

/// 组件来源分类
#[derive(Debug, Clone, PartialEq)]
pub enum SourceCategory {
    /// 开源项目组件（可通过 CDN 自动下载）
    OpenSource,
    /// 本地源码组件
    LocalSource,
    /// 未知来源，需要用户提供源码位置
    Unknown,
}

/// Vue SFC 解析结果（包含展开的子组件和动态特性）
pub struct ParsedVueSFC {
    /// 组件名称
    pub name: String,
    /// Template HTML（已展开子组件 + 添加 _iris 后缀）
    pub template_html: String,
    /// Script 内容（已注入动态特性）
    pub script_content: String,
    /// 原始 HTML（未加后缀）
    pub original_html: String,
    /// CSS 样式列表
    pub styles: Vec<String>,
    /// 子组件映射
    pub child_components: HashMap<String, ParsedVueSFC>,
}

/// Vue 组件加载器
pub struct VueComponentLoader {
    /// 组件注册表（用于下载开源组件）
    registry: Option<ComponentRegistry>,
    /// 基础路径（用于解析相对导入）
    #[allow(dead_code)]
    base_path: PathBuf,
}

impl VueComponentLoader {
    /// 创建新的加载器
    pub fn new(base_path: PathBuf) -> Self {
        Self {
            registry: None,
            base_path,
        }
    }

    /// 设置组件注册表
    pub fn with_registry(mut self, registry: ComponentRegistry) -> Self {
        self.registry = Some(registry);
        self
    }

    /// 加载并解析 Vue SFC 文件（递归展开子组件）
    pub fn load_and_parse<P: AsRef<Path>>(&mut self, vue_path: P) -> Result<ParsedVueSFC, String> {
        let vue_path = vue_path.as_ref();
        info!(path = ?vue_path, "Loading Vue SFC...");

        // 1. 读取源文件
        let source = std::fs::read_to_string(vue_path)
            .map_err(|e| format!("Failed to read Vue file: {}", e))?;

        // 2. 解析 SFC
        self.parse_sfc(&source, vue_path, &mut HashMap::new())
    }

    /// 解析 SFC（递归展开子组件）
    fn parse_sfc(
        &mut self,
        source: &str,
        current_path: &Path,
        loaded_components: &mut HashMap<String, ParsedVueSFC>,
    ) -> Result<ParsedVueSFC, String> {
        // 1. 提取各个部分
        let template = Self::extract_section(source, "template")
            .unwrap_or_default();
        let script = Self::extract_section(source, "script")
            .unwrap_or_default();
        let styles = Self::extract_all_sections(source, "style");

        // 2. 提取组件名
        let name = Self::extract_component_name(&script)
            .unwrap_or_else(|| {
                current_path.file_stem()
                    .and_then(|s| s.to_str())
                    .unwrap_or("Anonymous")
                    .to_string()
            });

        // 3. 解析 import 语句（增强版，支持多种导入类型）
        let imports = Self::parse_imports_enhanced(&script, current_path);
        debug!(component = name, imports_count = imports.len(), "Found imports");

        // 4. 递归加载子组件，并收集未解析的组件
        let mut child_components = HashMap::new();
        let mut unresolved_components: Vec<(String, String)> = Vec::new();

        for import_info in imports {
            if loaded_components.contains_key(&import_info.component_name) {
                debug!(component = import_info.component_name, "Already loaded, skipping");
                continue;
            }

            info!(
                component = import_info.component_name,
                import_type = ?import_info.import_type,
                "Loading child component"
            );

            // 判断组件来源类型
            let category = self.classify_source(&import_info);

            match category {
                SourceCategory::OpenSource => {
                    // 开源项目：尝试从注册表/CDN 下载
                    match self.fetch_open_source_component(&import_info) {
                        Ok(child_source) => {
                            let child_path = PathBuf::from(&import_info.raw_import);
                            match self.parse_sfc(&child_source, &child_path, loaded_components) {
                                Ok(child_sfc) => {
                                    child_components.insert(import_info.component_name.clone(), child_sfc);
                                }
                                Err(e) => {
                                    let msg = format!("Failed to parse open-source component '{}': {}", import_info.component_name, e);
                                    unresolved_components.push((import_info.component_name.clone(), msg));
                                }
                            }
                        }
                        Err(e) => {
                            let msg = format!("Cannot download open-source component '{}': {}. Please check your network or provide local source path.", import_info.component_name, e);
                            unresolved_components.push((import_info.component_name.clone(), msg));
                        }
                    }
                }
                SourceCategory::LocalSource => {
                    // 本地源码：从文件系统读取
                    match std::fs::read_to_string(&import_info.resolved_path) {
                        Ok(child_source) => {
                            match self.parse_sfc(&child_source, &import_info.resolved_path, loaded_components) {
                                Ok(child_sfc) => {
                                    child_components.insert(import_info.component_name.clone(), child_sfc);
                                }
                                Err(e) => {
                                    let msg = format!("Failed to parse local component '{}' at '{}': {}", import_info.component_name, import_info.resolved_path.display(), e);
                                    unresolved_components.push((import_info.component_name.clone(), msg));
                                }
                            }
                        }
                        Err(e) => {
                            let msg = format!("Cannot read local component '{}' at '{}': {}. Please ensure the file exists.", import_info.component_name, import_info.resolved_path.display(), e);
                            unresolved_components.push((import_info.component_name.clone(), msg));
                        }
                    }
                }
                SourceCategory::Unknown => {
                    // 未知来源：标记为未解析，提示用户输入源码位置
                    let msg = format!(
                        "Component '{}' from '{}' is from an unknown source. \
                         Please provide the source code location.\n\
                         - For open-source packages, try: npm install <package-name>\n\
                         - For local files, ensure the path is correct.\n\
                         - Or place the .vue file at: {}",
                        import_info.component_name,
                        import_info.raw_import,
                        import_info.resolved_path.display()
                    );
                    unresolved_components.push((import_info.component_name.clone(), msg));
                    debug!(component = import_info.component_name, "Unresolved component — needs user input");
                }
            }
        }

        // 5. 展开 template 中的子组件标签
        let expanded_template = Self::expand_components_in_template(&template, &child_components);

        // 6. 应用动态特性注入（包含未解析组件的异常标记）
        let (enhanced_html, enhanced_script) = crate::vue_dynamic::enhance_vue_sfc(
            &expanded_template,
            &script,
            &unresolved_components,
        );

        // 7. 缓存
        loaded_components.insert(name.clone(), ParsedVueSFC {
            name: name.clone(),
            template_html: enhanced_html.clone(),
            script_content: enhanced_script.clone(),
            original_html: expanded_template.clone(),
            styles: styles.clone(),
            child_components: HashMap::new(),
        });

        Ok(ParsedVueSFC {
            name,
            template_html: enhanced_html,
            script_content: enhanced_script,
            original_html: expanded_template,
            styles,
            child_components,
        })
    }

    /// 分类组件来源
    fn classify_source(&self, import: &ImportInfo) -> SourceCategory {
        match import.import_type {
            ImportType::Local => {
                // 本地文件：检查文件是否存在
                if import.resolved_path.exists() {
                    SourceCategory::LocalSource
                } else {
                    SourceCategory::Unknown
                }
            }
            ImportType::Url => {
                // URL 导入：尝试下载（暂归类为开源）
                SourceCategory::OpenSource
            }
            ImportType::Package | ImportType::ScopedPackage | ImportType::Named { .. } => {
                // 检查是否已知的开源包
                if let Some(ref registry) = self.registry {
                    if registry.is_known_package(&import.raw_import) {
                        SourceCategory::OpenSource
                    } else {
                        // 不在注册表中的包：尝试从 CDN 自动解析
                        SourceCategory::OpenSource
                    }
                } else {
                    // 无注册表：尝试从默认 CDN 自动解析
                    SourceCategory::OpenSource
                }
            }
        }
    }

    /// 获取开源组件源码
    fn fetch_open_source_component(&mut self, import: &ImportInfo) -> Result<String, String> {
        if let Some(ref mut registry) = self.registry {
            // 优先使用注册表
            match registry.fetch_component_source(&import.component_name) {
                Ok(source) => return Ok(source),
                Err(_) => {
                    // 注册表未命中：尝试从 CDN 下载
                    if let Ok(source) = Self::try_cdn_download(&import.raw_import, &import.component_name) {
                        // 缓存到注册表
                        registry.cache_source(&import.component_name, &source)?;
                        return Ok(source);
                    }
                }
            }
        }

        // 无注册表：尝试 CDN
        Self::try_cdn_download(&import.raw_import, &import.component_name)
    }

    /// 从 NPM CDN (unpkg/jsdelivr) 尝试下载组件源码
    fn try_cdn_download(package_spec: &str, component_name: &str) -> Result<String, String> {
        let client = reqwest::blocking::Client::builder()
            .timeout(std::time::Duration::from_secs(15))
            .build()
            .map_err(|e| format!("Failed to create HTTP client: {}", e))?;

        // 尝试多个 CDN 来源
        let cdn_urls = vec![
            // 从 unpkg 获取
            format!("https://unpkg.com/{}/dist/components/{}", package_spec, component_name),
            format!("https://unpkg.com/{}/dist/{}.vue", package_spec, component_name),
            format!("https://unpkg.com/{}/es/{}", package_spec, component_name),
            // 从 jsdelivr 获取
            format!("https://cdn.jsdelivr.net/npm/{}/dist/components/{}", package_spec, component_name),
            format!("https://cdn.jsdelivr.net/npm/{}/dist/{}.vue", package_spec, component_name),
            format!("https://cdn.jsdelivr.net/npm/{}/es/{}", package_spec, component_name),
        ];

        for url in &cdn_urls {
            debug!(url = %url, "Trying CDN download");
            match client.get(url).send() {
                Ok(response) if response.status().is_success() => {
                    let source = response.text()
                        .map_err(|e| format!("Failed to read response: {}", e))?;
                    info!(component = component_name, url = %url, "Successfully downloaded from CDN");
                    return Ok(source);
                }
                _ => continue,
            }
        }

        Err(format!(
            "Could not download '{}' from CDN. \
             If this is an open-source package, try:\n\
             1. npm install {}\n\
             2. Provide the .vue file at the expected path.\n\
             If this is a local component, use a relative import: './{}.vue'",
            component_name, package_spec, component_name
        ))
    }

    /// 展开 template 中的子组件标签
    fn expand_components_in_template(
        template: &str,
        child_components: &HashMap<String, ParsedVueSFC>,
    ) -> String {
        let mut result = template.to_string();

        for (component_name, child_sfc) in child_components {
            let patterns = vec![
                format!(r"<{}\s+([^>]*)/\\s*>", component_name),
                format!(r"<{}\s*/\\s*>", component_name),
                format!(r"<{}\s+[^>]*>(.*?)</{}\\s*>", component_name, component_name),
                format!(r"<{}>(.*?)</{}\\s*>", component_name, component_name),
            ];

            for pattern in patterns {
                if let Ok(re) = regex::Regex::new(&pattern) {
                    let replacement = format!("<div class=\"component-{}\">{}</div>",
                        component_name.to_lowercase(),
                        child_sfc.template_html);
                    result = re.replace_all(&result, &replacement).to_string();
                }
            }
        }

        result
    }

    /// 增强版 import 解析（支持多种导入类型）
    fn parse_imports_enhanced(script: &str, base_path: &Path) -> Vec<ImportInfo> {
        let mut imports = Vec::new();

        // 匹配: import ComponentName from 'module'
        let default_import_re = regex::Regex::new(
            r#"import\s+(\w+)\s+from\s+['"]([^'"]+)['"]"#
        ).expect("Invalid regex");

        for cap in default_import_re.captures_iter(script) {
            let component_name = cap[1].to_string();
            let raw_import = cap[2].to_string();
            let (import_type, resolved_path) = Self::resolve_import_path(&raw_import, base_path);

            imports.push(ImportInfo {
                component_name,
                raw_import,
                import_type,
                resolved_path,
            });
        }

        // 匹配: import { X } from 'module'  (具名导入)
        let named_import_re = regex::Regex::new(
            r#"import\s*\{([^}]+)\}\s*from\s+['"]([^'"]+)['"]"#
        ).expect("Invalid regex");

        for cap in named_import_re.captures_iter(script) {
            let names_str = cap[1].to_string();
            let package_name = cap[2].to_string();

            for name in names_str.split(',') {
                let name = name.trim().to_string();
                if name.is_empty() { continue; }
                // 处理 as 别名: X as Y
                let component_name = if let Some(as_pos) = name.find(" as ") {
                    name[as_pos + 4..].trim().to_string()
                } else {
                    name.clone()
                };

                let (_import_type, resolved_path) = Self::resolve_import_path(&package_name, base_path);
                imports.push(ImportInfo {
                    component_name,
                    raw_import: package_name.clone(),
                    import_type: ImportType::Named { package_name: package_name.clone() },
                    resolved_path,
                });
            }
        }

        imports
    }

    /// 解析导入路径，判断导入类型
    fn resolve_import_path(raw_path: &str, base_path: &Path) -> (ImportType, PathBuf) {
        // URL 导入
        if raw_path.starts_with("https://") || raw_path.starts_with("http://") {
            return (ImportType::Url, PathBuf::from(raw_path));
        }

        // 相对路径/绝对路径导入
        if raw_path.starts_with('.') || raw_path.starts_with('/') || raw_path.contains(".vue") {
            let resolved = base_path.parent()
                .unwrap_or(Path::new("."))
                .join(raw_path);
            return (ImportType::Local, resolved);
        }

        // Scoped 包名: @scope/package
        if raw_path.starts_with('@') && raw_path.contains('/') {
            return (ImportType::ScopedPackage, PathBuf::from(raw_path));
        }

        // 普通 npm 包名
        (ImportType::Package, PathBuf::from(raw_path))
    }

    /// 提取 section
    fn extract_section(source: &str, tag: &str) -> Result<String, String> {
        let start_tag = format!("<{}", tag);
        let end_tag = format!("</{}>", tag);

        let start = source.find(&start_tag)
            .ok_or_else(|| format!("Missing <{}> tag", tag))?;

        let content_start = source[start..].find('>')
            .map(|i| start + i + 1)
            .ok_or_else(|| format!("Invalid <{}> tag", tag))?;

        let end = source.find(&end_tag)
            .ok_or_else(|| format!("Missing </{}> tag", tag))?;

        Ok(source[content_start..end].to_string())
    }

    fn extract_all_sections(source: &str, tag: &str) -> Vec<String> {
        let mut results = Vec::new();
        let mut remaining = source;

        while let Ok(section) = Self::extract_section(remaining, tag) {
            results.push(section);
            if let Some(pos) = remaining.find(&format!("</{}>", tag)) {
                remaining = &remaining[pos + format!("</{}>", tag).len()..];
            } else {
                break;
            }
        }

        results
    }

    /// 提取组件名
    fn extract_component_name(script: &str) -> Option<String> {
        let re = regex::Regex::new("name:\\s*['\"](\\w+)['\"]").ok()?;
        re.captures(script).map(|cap| cap[1].to_string())
    }
}

/// 组件注册表（管理开源组件下载和缓存）
pub struct ComponentRegistry {
    /// 已知开源包列表 (package_name -> metadata)
    known_packages: HashMap<String, PackageInfo>,
    /// 已知组件注册表 (component_name -> source_url)
    registry: HashMap<String, String>,
    /// 缓存目录
    cache_dir: PathBuf,
    /// HTTP 客户端
    client: reqwest::blocking::Client,
}

/// 包信息
#[derive(Debug, Clone)]
pub struct PackageInfo {
    pub name: String,
    pub version: Option<String>,
    pub source_type: PackageSource,
    pub cdn_url: Option<String>,
}

/// 包来源类型
#[derive(Debug, Clone)]
pub enum PackageSource {
    /// NPM 包
    Npm,
    /// GitHub 仓库
    GitHub { owner: String, repo: String },
    /// 自定义 URL
    Custom(String),
}

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 dir: {}", e))?;

        let mut reg = Self {
            known_packages: HashMap::new(),
            registry: HashMap::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))?,
        };

        // 注册常用开源 UI 库
        reg.register_known_packages();

        Ok(reg)
    }

    /// 注册常用开源 UI 库
    fn register_known_packages(&mut self) {
        let common_packages = vec![
            // Element Plus
            ("element-plus", PackageSource::Npm),
            ("naive-ui", PackageSource::Npm),
            ("ant-design-vue", PackageSource::Npm),
            ("view-ui-plus", PackageSource::Npm),
            ("vant", PackageSource::Npm),
            ("vuetify", PackageSource::Npm),
            ("primevue", PackageSource::Npm),
            ("quasar", PackageSource::Npm),
            ("bootstrap-vue", PackageSource::Npm),
            ("vue-echarts", PackageSource::Npm),
            ("vue-router", PackageSource::Npm),
            ("pinia", PackageSource::Npm),
            ("@vueuse/core", PackageSource::Npm),
            ("@vueuse/components", PackageSource::Npm),
            ("@vue/compat", PackageSource::Npm),
        ];

        for (name, source) in common_packages {
            self.known_packages.insert(name.to_string(), PackageInfo {
                name: name.to_string(),
                version: None,
                source_type: source,
                cdn_url: None,
            });
        }
    }

    /// 检查是否为已知的开源包
    pub fn is_known_package(&self, package_name: &str) -> bool {
        self.known_packages.contains_key(package_name)
    }

    /// 缓存组件源码
    pub fn cache_source(&mut self, component_name: &str, source: &str) -> Result<(), String> {
        let cache_path = self.cache_dir.join(format!("{}.vue", component_name));
        std::fs::write(&cache_path, source)
            .map_err(|e| format!("Failed to cache component: {}", e))
    }

    /// 加载注册表文件
    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: {}", e))?;

        let json: serde_json::Value = serde_json::from_str(&content)
            .map_err(|e| format!("Failed to parse JSON: {}", e))?;

        if let Some(libraries) = json.get("libraries") {
            for (_, lib_data) in libraries.as_object().unwrap_or(&serde_json::Map::new()) {
                // 注册包信息
                if let Some(pkg_name) = lib_data.get("package").and_then(|v| v.as_str()) {
                    self.known_packages.insert(pkg_name.to_string(), PackageInfo {
                        name: pkg_name.to_string(),
                        version: lib_data.get("version").and_then(|v| v.as_str()).map(|s| s.to_string()),
                        source_type: PackageSource::Npm,
                        cdn_url: None,
                    });
                }

                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(url) = comp_data.get("source_url").and_then(|v| v.as_str()) {
                            self.registry.insert(comp_name.clone(), url.to_string());
                        }
                    }
                }
            }
        }

        Ok(())
    }

    /// 获取组件源码
    pub fn fetch_component_source(&mut self, component_name: &str) -> Result<String, String> {
        // 1. 检查缓存
        let cache_path = self.cache_dir.join(format!("{}.vue", component_name));
        if cache_path.exists() {
            return std::fs::read_to_string(&cache_path)
                .map_err(|e| format!("Failed to read cache: {}", e));
        }

        // 2. 从注册表获取 URL
        let url = self.registry.get(component_name)
            .ok_or_else(|| format!("Component '{}' not in registry", component_name))?
            .clone();

        // 3. 下载
        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 {}", response.status(), url));
        }

        let source = response.text()
            .map_err(|e| format!("Failed to read response: {}", e))?;

        // 4. 缓存
        std::fs::write(&cache_path, &source)
            .map_err(|e| format!("Failed to cache: {}", e))?;

        Ok(source)
    }

    /// 获取已知开源包列表
    pub fn known_packages(&self) -> Vec<&str> {
        self.known_packages.keys().map(|s| s.as_str()).collect()
    }
}