use crate::error::PluginResult;
use crate::manifest::PluginManifest;

/// 插件上传时校验报告
#[derive(Debug, Clone, serde::Serialize)]
pub struct ValidationReport {
    pub valid: bool,
    pub errors: Vec<String>,
    pub warnings: Vec<String>,
    pub metrics: PluginMetrics,
}

/// 插件质量指标
#[derive(Debug, Clone, Default, serde::Serialize)]
pub struct PluginMetrics {
    pub entity_count: usize,
    pub field_count: usize,
    pub page_count: usize,
    pub permission_count: usize,
    pub relation_count: usize,
    pub has_import_export: bool,
    pub has_settings: bool,
    pub has_numbering: bool,
    pub has_trigger_events: bool,
    pub wasm_size_bytes: usize,
    pub complexity_score: f64,
}

/// 运行时监控指标
#[derive(Debug, Clone, Default, serde::Serialize)]
pub struct RuntimeMetrics {
    pub error_count: u64,
    pub total_invocations: u64,
    pub avg_response_ms: f64,
    pub fuel_consumption_avg: f64,
    pub memory_peak_bytes: u64,
    pub last_error: Option<String>,
    pub last_error_at: Option<chrono::DateTime<chrono::Utc>>,
}

impl RuntimeMetrics {
    pub fn error_rate(&self) -> f64 {
        if self.total_invocations == 0 {
            return 0.0;
        }
        self.error_count as f64 / self.total_invocations as f64
    }
}

/// 上传时安全扫描
pub fn validate_plugin_security(
    manifest: &PluginManifest,
    wasm_size: usize,
) -> PluginResult<ValidationReport> {
    let mut errors = Vec::new();
    let mut warnings = Vec::new();

    // 1. WASM 大小检查（上限 10MB）
    if wasm_size > 10 * 1024 * 1024 {
        errors.push(format!("WASM 文件过大: {} bytes (上限 10MB)", wasm_size));
    } else if wasm_size > 5 * 1024 * 1024 {
        warnings.push(format!("WASM 文件较大: {} bytes (>5MB)", wasm_size));
    }

    // 2. 实体数量检查（上限 20）
    if let Some(schema) = &manifest.schema {
        if schema.entities.len() > 20 {
            errors.push(format!("实体数量过多: {} (上限 20)", schema.entities.len()));
        }

        for entity in &schema.entities {
            // 字段数量检查
            if entity.fields.len() > 50 {
                errors.push(format!(
                    "实体 '{}' 字段数量过多: {} (上限 50)",
                    entity.name,
                    entity.fields.len()
                ));
            }

            // 索引数量检查
            if entity.indexes.len() > 10 {
                warnings.push(format!(
                    "实体 '{}' 索引数量较多: {} (>10 可能影响写入性能)",
                    entity.name,
                    entity.indexes.len()
                ));
            }

            // 检查字段中有无潜在 SQL 注入风险的字段名
            for field in &entity.fields {
                if field.name.len() > 64 {
                    errors.push(format!(
                        "字段名过长: '{}.{}' (上限 64 字符)",
                        entity.name, field.name
                    ));
                }
                if !field
                    .name
                    .chars()
                    .all(|c| c.is_ascii_alphanumeric() || c == '_')
                {
                    errors.push(format!(
                        "字段名包含非法字符: '{}.{}' (只允许字母、数字、下划线)",
                        entity.name, field.name
                    ));
                }
            }
        }
    }

    // 3. 权限码命名规范检查
    if let Some(permissions) = &manifest.permissions {
        for perm in permissions {
            if !perm.code.contains('.') {
                warnings.push(format!(
                    "权限码 '{}' 建议使用 'entity.action' 格式",
                    perm.code
                ));
            }
        }
    }

    // 4. 依赖检查
    if manifest.metadata.dependencies.len() > 5 {
        warnings.push(format!(
            "依赖数量较多: {} (>5 可能增加安装复杂度)",
            manifest.metadata.dependencies.len()
        ));
    }

    // 5. 计算复杂度分数
    let mut metrics = collect_metrics(manifest, wasm_size);
    metrics.complexity_score = calculate_complexity_score(&metrics);

    if metrics.complexity_score > 80.0 {
        warnings.push(format!(
            "插件复杂度较高: {:.1} (>80 建议拆分)",
            metrics.complexity_score
        ));
    }

    let valid = errors.is_empty();
    Ok(ValidationReport {
        valid,
        errors,
        warnings,
        metrics,
    })
}

/// 收集插件指标
fn collect_metrics(manifest: &PluginManifest, wasm_size: usize) -> PluginMetrics {
    let mut metrics = PluginMetrics {
        wasm_size_bytes: wasm_size,
        ..Default::default()
    };

    if let Some(schema) = &manifest.schema {
        metrics.entity_count = schema.entities.len();
        for entity in &schema.entities {
            metrics.field_count += entity.fields.len();
            metrics.relation_count += entity.relations.len();
            if entity.importable == Some(true) || entity.exportable == Some(true) {
                metrics.has_import_export = true;
            }
        }
    }

    if let Some(ui) = &manifest.ui {
        metrics.page_count = count_pages(&ui.pages);
    }

    if let Some(permissions) = &manifest.permissions {
        metrics.permission_count = permissions.len();
    }

    metrics.has_settings = manifest.settings.is_some();
    metrics.has_numbering = manifest.numbering.as_ref().is_some_and(|n| !n.is_empty());
    metrics.has_trigger_events = manifest
        .trigger_events
        .as_ref()
        .is_some_and(|t| !t.is_empty());

    metrics
}

fn count_pages(pages: &[crate::manifest::PluginPageType]) -> usize {
    let mut count = 0;
    for page in pages {
        count += 1;
        if let crate::manifest::PluginPageType::Tabs { tabs, .. } = page {
            count += count_pages(tabs);
        }
    }
    count
}

/// 计算复杂度分数（0-100）
fn calculate_complexity_score(metrics: &PluginMetrics) -> f64 {
    let entity_score = (metrics.entity_count as f64 / 20.0) * 30.0;
    let field_score = (metrics.field_count as f64 / 100.0) * 20.0;
    let page_score = (metrics.page_count as f64 / 20.0) * 15.0;
    let relation_score = (metrics.relation_count as f64 / 30.0) * 15.0;
    let size_score = (metrics.wasm_size_bytes as f64 / (10.0 * 1024.0 * 1024.0)) * 20.0;

    (entity_score + field_score + page_score + relation_score + size_score).min(100.0)
}

/// 性能基准测试结果
#[derive(Debug, Clone, serde::Serialize)]
pub struct BenchmarkResult {
    pub create_avg_ms: f64,
    pub read_avg_ms: f64,
    pub update_avg_ms: f64,
    pub delete_avg_ms: f64,
    pub list_avg_ms: f64,
    pub passed: bool,
    pub details: String,
}

impl BenchmarkResult {
    /// 创建操作的阈值: 500ms
    pub const CREATE_THRESHOLD_MS: f64 = 500.0;
    /// 读取操作的阈值: 200ms
    pub const READ_THRESHOLD_MS: f64 = 200.0;
    /// 列表查询的阈值: 1000ms
    pub const LIST_THRESHOLD_MS: f64 = 1000.0;

    pub fn check(&self) -> bool {
        self.create_avg_ms <= Self::CREATE_THRESHOLD_MS
            && self.read_avg_ms <= Self::READ_THRESHOLD_MS
            && self.list_avg_ms <= Self::LIST_THRESHOLD_MS
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::manifest::parse_manifest;

    #[test]
    fn validate_security_basic() {
        let toml = r#"
[metadata]
id = "test"
name = "Test"
version = "0.1.0"

[schema]
[[schema.entities]]
name = "product"
display_name = "商品"

[[schema.entities.fields]]
name = "sku"
field_type = "string"
required = true
"#;
        let manifest = parse_manifest(toml).unwrap();
        let report = validate_plugin_security(&manifest, 1024).unwrap();
        assert!(report.valid);
        assert!(report.errors.is_empty());
    }

    #[test]
    fn reject_oversized_wasm() {
        let toml = r#"
[metadata]
id = "test"
name = "Test"
version = "0.1.0"
"#;
        let manifest = parse_manifest(toml).unwrap();
        let report = validate_plugin_security(&manifest, 15 * 1024 * 1024).unwrap();
        assert!(!report.valid);
        assert!(report.errors.iter().any(|e| e.contains("WASM 文件过大")));
    }

    #[test]
    fn complexity_score_calculation() {
        let metrics = PluginMetrics {
            entity_count: 5,
            field_count: 30,
            page_count: 5,
            relation_count: 3,
            wasm_size_bytes: 500_000,
            ..Default::default()
        };
        let score = calculate_complexity_score(&metrics);
        assert!(score > 0.0 && score < 50.0, "score = {}", score);
    }

    #[test]
    fn runtime_metrics_error_rate() {
        let metrics = RuntimeMetrics {
            error_count: 5,
            total_invocations: 100,
            ..Default::default()
        };
        assert!((metrics.error_rate() - 0.05).abs() < 0.001);
    }

    #[test]
    fn benchmark_threshold_check() {
        let result = BenchmarkResult {
            create_avg_ms: 300.0,
            read_avg_ms: 100.0,
            update_avg_ms: 200.0,
            delete_avg_ms: 150.0,
            list_avg_ms: 800.0,
            passed: true,
            details: String::new(),
        };
        assert!(result.check());
    }
}
