/**
 * Agent Runtime Layer — Reporting
 *
 * PR-35 Part F：统一报告生成。
 *
 * 报告类型：
 *   - Task Report        — 任务摘要
 *   - Execution Report   — 步骤详情
 *   - Quality Report     — Checklist + Baseline
 *   - Certification Report — 认证结果
 *   - Risk Report        — 风险清单
 *
 * 纯函数，无副作用。
 *
 * @module agent-runtime/reporting
 */

import { PIPELINE_STAGE } from "./domain.mjs";

// ═══════════════════════════════════════════════════════
// 主报告
// ═══════════════════════════════════════════════════════

/**
 * 生成完整 Runtime 报告（Markdown）。
 *
 * @param {object} task       — Task 对象
 * @param {object} taskResult — TaskResult (executePipeline 返回值)
 * @returns {string} Markdown
 */
export function generateRuntimeReport(task, taskResult) {
  if (!task || !taskResult) return _errorReport("Invalid input: task or taskResult is null/undefined");

  const sections = [
    _taskSection(task, taskResult),
    _executionSection(task, taskResult),
    _artifactsSection(taskResult),
    _qualitySection(taskResult),
    _certificationSection(taskResult),
    _riskSection(taskResult),
    _observationsSection(taskResult),
    _metricsSection(taskResult),
    _nextActionSection(taskResult),
  ];

  return `# Agent Runtime Execution Report\n\n${sections.join("\n")}\n---\n_Generated at ${new Date().toISOString()}_\n`;
}

// ═══════════════════════════════════════════════════════
// Section: Task
// ═══════════════════════════════════════════════════════

function _taskSection(task, tr) {
  const icon = _statusIcon(tr.status);
  const lines = [
    "## Task Information",
    "",
    "| Field | Value |",
    "|-------|-------|",
    `| Task ID | \`${task.id}\` |`,
    `| Title | ${task.title} |`,
    `| Status | ${icon} **${(tr.status || "unknown").toUpperCase()}** |`,
  ];
  if (task.description) lines.push(`| Description | ${task.description} |`);
  if (task.tags?.length) lines.push(`| Tags | ${task.tags.join(", ")} |`);
  if (task.parentTaskId) lines.push(`| Parent Task | \`${task.parentTaskId}\` |`);
  if (tr.durationMs != null) lines.push(`| Duration | ${tr.durationMs}ms |`);
  lines.push(`| Steps | ${tr.executedSteps?.length || 0} executed |`);
  lines.push(`| Artifacts | ${tr.artifactIds?.length || 0} generated |`);
  lines.push(`| Changed Files | ${tr.changedFiles?.length || 0} |`);
  if (task.retryCount > 0) lines.push(`| Retries | ${task.retryCount}/${task.maxRetries} |`);
  lines.push("");
  return lines.join("\n");
}

// ═══════════════════════════════════════════════════════
// Section: Execution
// ═══════════════════════════════════════════════════════

function _executionSection(task, tr) {
  const lines = ["## Executed Steps", ""];
  const steps = tr.executedSteps || [];

  if (steps.length === 0) {
    lines.push("_No steps executed._\n");
    return lines.join("\n");
  }

  lines.push("| # | Step ID | Status | Changed Files | Details |");
  lines.push("|---|---------|--------|---------------|---------|");
  steps.forEach((s, i) => {
    const icon = s.status === "completed" ? "✅" : s.status === "failed" ? "❌" : "⏭️";
    const files = (s.changedFiles || []).join(", ") || "—";
    const detail = s.status === "completed"
      ? (typeof s.output === "string" ? _truncate(s.output, 60) : "—")
      : s.status === "failed"
        ? `Error: ${_truncate(s.error || "unknown", 60)}`
        : s.reason || "—";
    lines.push(`| ${i + 1} | \`${s.stepId}\` | ${icon} ${s.status} | ${files} | ${detail} |`);
  });
  lines.push("");

  // Summary
  const plan = task.executionPlan;
  if (plan?.steps) {
    const summary = _stepSummary(plan.steps);
    lines.push(`**Step Summary:** Total: ${summary.total} | ✅ Completed: ${summary.completed} | ❌ Failed: ${summary.failed} | ⏭️ Skipped: ${summary.skipped} | ⏳ Pending: ${summary.pending}`);
    lines.push("");
  }

  // Changed files
  if (tr.changedFiles?.length) {
    lines.push("**Changed Files:**");
    tr.changedFiles.forEach(f => lines.push(`- \`${f}\``));
    lines.push("");
  }

  return lines.join("\n");
}

// ═══════════════════════════════════════════════════════
// Section: Artifacts
// ═══════════════════════════════════════════════════════

function _artifactsSection(tr) {
  const lines = ["## Artifacts", ""];
  const ids = tr.artifactIds || [];
  if (ids.length === 0) {
    lines.push("_No artifacts generated._\n");
  } else {
    ids.forEach(id => lines.push(`- \`${id}\``));
    lines.push("");
  }
  return lines.join("\n");
}

// ═══════════════════════════════════════════════════════
// Section: Quality (Checklist + Baseline + Gate)
// ═══════════════════════════════════════════════════════

function _qualitySection(tr) {
  const lines = ["## Quality Report", ""];

  // Checklist
  lines.push("### Checklist Result");
  lines.push("");
  if (tr.checklistResult) {
    const c = tr.checklistResult;
    const icon = c.status === "pass" ? "✅" : c.status === "warn" ? "⚠️" : "❌";
    lines.push(`Status: ${icon} **${(c.status || "unknown").toUpperCase()}**`);
    if (c.confidence != null) lines.push(`Confidence: **${c.confidence}/100**`);
    if (c.blockers?.length) { lines.push(""); c.blockers.forEach(b => lines.push(`- ❌ ${b}`)); }
    if (c.warnings?.length) { lines.push(""); c.warnings.forEach(w => lines.push(`- ⚠️ ${w}`)); }
  } else {
    lines.push("_Not executed._");
  }
  lines.push("");

  // Baseline
  lines.push("### Baseline Comparison");
  lines.push("");
  if (tr.baselineComparison) {
    const b = tr.baselineComparison;
    const icon = b.status === "pass" ? "✅" : b.status === "warn" ? "⚠️" : "❌";
    lines.push(`Status: ${icon} **${(b.status || "unknown").toUpperCase()}**`);
    if (b.changes?.length) {
      lines.push("");
      lines.push("| Metric | Baseline | Candidate | Delta | Δ% |");
      lines.push("|--------|----------|-----------|-------|-----|");
      b.changes.forEach(c => {
        const sign = c.delta > 0 ? "+" : "";
        const absPct = Math.abs(c.deltaPercent || 0);
        const pIcon = absPct > 50 ? "🔴" : absPct > 20 ? "🟡" : "";
        lines.push(`| ${c.label || c.metric} | ${c.baseline} | ${c.candidate} | ${sign}${c.delta} | ${pIcon} ${sign}${c.deltaPercent}% |`);
      });
    }
    if (b.blockers?.length) { lines.push(""); b.blockers.forEach(x => lines.push(`- ❌ ${x}`)); }
    if (b.warnings?.length) { lines.push(""); b.warnings.forEach(x => lines.push(`- ⚠️ ${x}`)); }
  } else {
    lines.push("_Not executed._");
  }
  lines.push("");

  // Gate
  lines.push("### Gate Decision");
  lines.push("");
  if (tr.gateDecision) {
    const g = tr.gateDecision;
    const icon = g.decision === "OPEN" ? "🟢" : "🔴";
    lines.push(`Decision: ${icon} **${g.decision}**`);
    if (g.summary) lines.push(`Summary: ${g.summary}`);
    if (g.blockers?.length) { lines.push(""); g.blockers.forEach(b => lines.push(`- ❌ ${b}`)); }
    if (g.warnings?.length) { lines.push(""); g.warnings.forEach(w => lines.push(`- ⚠️ ${w}`)); }
  } else {
    lines.push("_Not executed._");
  }
  lines.push("");

  return lines.join("\n");
}

// ═══════════════════════════════════════════════════════
// Section: Certification
// ═══════════════════════════════════════════════════════

function _certificationSection(tr) {
  const lines = ["## Certification Report", ""];
  if (!tr.certification) {
    lines.push("_Not available._\n");
    return lines.join("\n");
  }
  const c = tr.certification;
  const icon = _certIcon(c.tier);
  lines.push(`Tier: ${icon} **${(c.tier || "none").toUpperCase()}**`);
  lines.push(`Score: **${c.score}/100**`);
  if (c.passedCriteria?.length) {
    lines.push("");
    lines.push("**Passed Criteria:**");
    c.passedCriteria.forEach(x => lines.push(`- ✅ ${x}`));
  }
  if (c.failedCriteria?.length) {
    lines.push("");
    lines.push("**Failed Criteria:**");
    c.failedCriteria.forEach(x => lines.push(`- ❌ ${x}`));
  }
  if (c.recommendation) {
    lines.push("");
    lines.push(`> ${c.recommendation}`);
  }
  lines.push("");
  return lines.join("\n");
}

// ═══════════════════════════════════════════════════════
// Section: Risk
// ═══════════════════════════════════════════════════════

function _riskSection(tr) {
  const lines = ["## Risk Report", ""];
  const risks = tr.risks || [];
  if (risks.length === 0) {
    lines.push("_No risks identified._\n");
    return lines.join("\n");
  }

  const byLevel = { critical: [], high: [], medium: [], low: [] };
  risks.forEach(r => { const key = r.level || "low"; if (byLevel[key]) byLevel[key].push(r); });

  lines.push("| Level | Count |");
  lines.push("|-------|-------|");
  for (const [level, items] of Object.entries(byLevel)) {
    if (items.length > 0) lines.push(`| ${_riskIcon(level)} ${level} | ${items.length} |`);
  }
  lines.push("");

  lines.push("| Risk ID | Level | Source | Description | Mitigation |");
  lines.push("|---------|-------|--------|-------------|------------|");
  risks.forEach(r => {
    lines.push(`| \`${r.id}\` | ${_riskIcon(r.level)} ${r.level} | ${r.source || "—"} | ${r.description} | ${r.mitigation || "—"} |`);
  });
  lines.push("");
  return lines.join("\n");
}

// ═══════════════════════════════════════════════════════
// Section: Observations
// ═══════════════════════════════════════════════════════

function _observationsSection(tr) {
  const lines = ["## Observations", ""];
  const obs = tr.observations || [];
  if (obs.length === 0) {
    lines.push("_No observations recorded._\n");
    return lines.join("\n");
  }
  obs.forEach(o => {
    const icon = o.severity === "error" ? "❌" : o.severity === "warn" ? "⚠️" : "ℹ️";
    lines.push(`- ${icon} [${o.stage}] ${o.message}`);
  });
  lines.push("");
  return lines.join("\n");
}

// ═══════════════════════════════════════════════════════
// Section: Metrics
// ═══════════════════════════════════════════════════════

function _metricsSection(tr) {
  const lines = ["## Metrics", ""];
  const metrics = tr.metrics || [];
  if (metrics.length === 0) {
    lines.push("_No metrics recorded._\n");
    return lines.join("\n");
  }
  lines.push("| Name | Value | Unit | Tags |");
  lines.push("|------|-------|------|------|");
  metrics.forEach(m => {
    const tags = Object.entries(m.tags || {}).map(([k, v]) => `${k}=${v}`).join(", ") || "—";
    lines.push(`| ${m.name} | ${m.value} | ${m.unit || "—"} | ${tags} |`);
  });
  lines.push("");
  return lines.join("\n");
}

// ═══════════════════════════════════════════════════════
// Section: Next Action
// ═══════════════════════════════════════════════════════

function _nextActionSection(tr) {
  const lines = ["## Recommended Next Action", ""];
  lines.push(`> ${tr.recommendedNextAction || "No recommendation."}`);
  lines.push("");
  return lines.join("\n");
}

// ═══════════════════════════════════════════════════════
// 子报告
// ═══════════════════════════════════════════════════════

/**
 * 生成仅 Task 摘要的子报告。
 */
export function generateTaskReport(task, taskResult) {
  return `# Task Report: ${task.title}\n\n${_taskSection(task, taskResult)}`;
}

/**
 * 生成仅质量报告的子报告。
 */
export function generateQualityReport(taskResult) {
  return `# Quality Report\n\n${_qualitySection(taskResult)}`;
}

/**
 * 生成仅认证报告的子报告。
 */
export function generateCertificationReport(taskResult) {
  return `# Certification Report\n\n${_certificationSection(taskResult)}`;
}

/**
 * 生成仅风险报告的子报告。
 */
export function generateRiskReport(taskResult) {
  return `# Risk Report\n\n${_riskSection(taskResult)}`;
}

// ═══════════════════════════════════════════════════════
// 内部工具
// ═══════════════════════════════════════════════════════

function _statusIcon(s) {
  switch (s) {
    case "passed":  return "✅";
    case "failed":  return "❌";
    case "blocked": return "🚫";
    case "cancelled": return "🚫";
    default:        return "❓";
  }
}

function _certIcon(t) {
  switch (t) {
    case "platinum": return "💎";
    case "gold":     return "🥇";
    case "silver":   return "🥈";
    case "bronze":   return "🥉";
    default:         return "❌";
  }
}

function _riskIcon(l) {
  switch (l) {
    case "critical": return "🔴";
    case "high":     return "🟠";
    case "medium":   return "🟡";
    case "low":      return "🟢";
    default:         return "⚪";
  }
}

function _truncate(s, max) {
  if (!s) return "—";
  return s.length <= max ? s : s.slice(0, max) + "...";
}

function _stepSummary(steps) {
  const s = { total: 0, completed: 0, failed: 0, skipped: 0, pending: 0, running: 0, blocked: 0 };
  for (const step of steps) {
    s.total++;
    switch (step.state) {
      case "completed": s.completed++; break;
      case "failed":    s.failed++;    break;
      case "skipped":   s.skipped++;   break;
      case "pending":   s.pending++;   break;
      case "running":   s.running++;   break;
      case "blocked":   s.blocked++;   break;
    }
  }
  return s;
}

function _errorReport(reason) {
  return `# Agent Runtime Execution Report\n\n## Task Information\n\n> ❌ ${reason}\n\n---\n_Generated at ${new Date().toISOString()}_\n`;
}
