/**
 * Agent Runtime Layer — Domain Model
 *
 * PR-35：统一数据模型，支撑 SF-01 ~ SF-15 全部 Software Factory。
 *
 * 设计原则：
 *   - 纯类型定义 + 工厂函数，无副作用
 *   - 支持任务继承、依赖、编排、重试、恢复
 *   - 不可变创建模式（工厂函数返回新对象）
 *
 * @module agent-runtime/domain
 */

// ═══════════════════════════════════════════════════════
// 状态常量
// ═══════════════════════════════════════════════════════

export const TASK_STATE = Object.freeze({
  CREATED:   "created",
  PLANNED:   "planned",
  QUEUED:    "queued",
  RUNNING:   "running",
  CHECKING:  "checking",
  PASSED:    "passed",
  FAILED:    "failed",
  BLOCKED:   "blocked",
  CANCELLED: "cancelled",
  ARCHIVED:  "archived",
});

export const STEP_STATE = Object.freeze({
  PENDING:   "pending",
  QUEUED:    "queued",
  RUNNING:   "running",
  COMPLETED: "completed",
  FAILED:    "failed",
  SKIPPED:   "skipped",
  BLOCKED:   "blocked",
});

export const PIPELINE_STAGE = Object.freeze({
  PLANNING:             "planning",
  EXECUTION:            "execution",
  CHECKLIST:            "checklist",
  BASELINE_COMPARISON:  "baseline_comparison",
  GATE_EVALUATION:      "gate_evaluation",
  CERTIFICATION:        "certification",
  ARTIFACT_GENERATION:  "artifact_generation",
  REPORTING:            "reporting",
});

export const RISK_LEVEL = Object.freeze({
  LOW:      "low",
  MEDIUM:   "medium",
  HIGH:     "high",
  CRITICAL: "critical",
});

export const CERTIFICATION_TIER = Object.freeze({
  NONE:     "none",
  BRONZE:   "bronze",
  SILVER:   "silver",
  GOLD:     "gold",
  PLATINUM: "platinum",
});

export const ARTIFACT_KIND = Object.freeze({
  DOCUMENT:     "document",
  CODE:         "code",
  ARCHITECTURE: "architecture",
  DESIGN:       "design",
  TEST:         "test",
  RELEASE:      "release",
  REPORT:       "report",
  METRIC:       "metric",
  OTHER:        "other",
});

export const GATE_DECISION = Object.freeze({
  OPEN:   "OPEN",
  CLOSED: "CLOSED",
  WARN:   "WARN",
});

// ═══════════════════════════════════════════════════════
// Task
// ═══════════════════════════════════════════════════════

let _taskSeq = 0;

/**
 * @param {object} p
 * @param {string} p.id
 * @param {string} p.title
 * @param {string} [p.description]
 * @param {string} [p.parentTaskId]  — 任务继承
 * @param {string[]} [p.dependsOn]   — 任务依赖
 * @param {string[]} [p.tags]
 * @param {object} [p.metadata]
 * @returns {object}
 */
export function createTask({ id, title, description = "", parentTaskId = null, dependsOn = [], tags = [], metadata = {} }) {
  if (!id) throw new TypeError("Task.id is required");
  if (!title) throw new TypeError("Task.title is required");

  return {
    id,
    title,
    description,
    state: TASK_STATE.CREATED,
    parentTaskId,
    dependsOn: [...dependsOn],
    tags: [...tags],
    metadata: { ...metadata },
    subTasks: [],
    executionPlan: null,
    artifacts: [],
    risks: [],
    observations: [],
    metrics: [],

    // 时间戳
    createdAt: new Date().toISOString(),
    plannedAt: null,
    startedAt: null,
    checkedAt: null,
    completedAt: null,
    archivedAt: null,

    // 审计
    stateHistory: [{ state: TASK_STATE.CREATED, at: new Date().toISOString() }],
    transitionLog: [],

    // 重试/恢复
    retryCount: 0,
    maxRetries: 3,
    recoveryStrategy: null,
  };
}

// ═══════════════════════════════════════════════════════
// SubTask
// ═══════════════════════════════════════════════════════

/**
 * @param {object} p
 * @param {string} p.id
 * @param {string} p.title
 * @param {string} p.parentTaskId
 * @param {number} [p.order]
 * @returns {object}
 */
export function createSubTask({ id, title, parentTaskId, order = 0 }) {
  const t = createTask({ id, title, parentTaskId });
  t._order = order;
  return t;
}

// ═══════════════════════════════════════════════════════
// ExecutionPlan
// ═══════════════════════════════════════════════════════

/**
 * @param {object} p
 * @param {string} p.taskId
 * @param {object[]} p.steps
 * @param {string} [p.strategy]  — "sequential" | "parallel" | "dependency-graph"
 * @returns {object}
 */
export function createExecutionPlan({ taskId, steps = [], strategy = "sequential" }) {
  return {
    taskId,
    strategy,
    steps: steps.map(s => createExecutionStep(s)),
    estimatedDurationMs: null,
    createdAt: new Date().toISOString(),
  };
}

// ═══════════════════════════════════════════════════════
// ExecutionStep
// ═══════════════════════════════════════════════════════

let _stepSeq = 0;

/**
 * @param {object} p
 * @param {string} [p.id]
 * @param {string} p.name
 * @param {string} p.action
 * @param {string[]} [p.dependsOn]
 * @param {string[]} [p.expectedArtifacts]
 * @param {object} [p.metadata]
 * @returns {object}
 */
export function createExecutionStep({ id, name, action, dependsOn = [], expectedArtifacts = [], metadata = {} }) {
  return {
    id: id || `step-${++_stepSeq}`,
    name,
    action,
    state: STEP_STATE.PENDING,
    dependsOn: [...dependsOn],
    expectedArtifacts: [...expectedArtifacts],
    metadata: { ...metadata },
    result: null,
    error: null,

    startedAt: null,
    completedAt: null,
    durationMs: null,

    retryCount: 0,
    maxRetries: 1,
  };
}

// ═══════════════════════════════════════════════════════
// ExecutionResult
// ═══════════════════════════════════════════════════════

/**
 * @param {object} p
 * @param {string} p.stepId
 * @param {"completed"|"failed"|"skipped"} p.status
 * @param {string[]} [p.changedFiles]
 * @param {string[]} [p.artifactIds]
 * @param {*} [p.output]
 * @param {string} [p.error]
 * @returns {object}
 */
export function createExecutionResult({ stepId, status, changedFiles = [], artifactIds = [], output = null, error = null }) {
  const start = Date.now();
  return {
    stepId,
    status,
    changedFiles: [...changedFiles],
    artifactIds: [...artifactIds],
    output,
    error,
    timestamp: new Date().toISOString(),
    _timer: start,
    markComplete() { this.durationMs = Date.now() - this._timer; delete this._timer; },
  };
}

// ═══════════════════════════════════════════════════════
// Artifact
// ═══════════════════════════════════════════════════════

let _artifactSeq = 0;

/**
 * @param {object} p
 * @param {string} [p.id]
 * @param {"document"|"code"|"architecture"|"design"|"test"|"release"|"report"|"metric"|"other"} p.kind
 * @param {string} p.name
 * @param {string} [p.path]
 * @param {string} [p.content]
 * @param {string} p.taskId
 * @param {string} [p.stepId]
 * @param {object} [p.metadata]
 * @returns {object}
 */
export function createArtifact({ id, kind, name, path = null, content = null, taskId, stepId = null, metadata = {} }) {
  if (!kind || !ARTIFACT_KIND[kind.toUpperCase()]) throw new TypeError(`Invalid artifact kind: ${kind}`);
  return {
    id: id || `artifact-${++_artifactSeq}`,
    kind,
    name,
    path,
    content,
    taskId,
    stepId,
    metadata: { ...metadata },
    createdAt: new Date().toISOString(),
    version: 1,
    parentArtifactId: null,
    checksum: null,  // set by registry
  };
}

// ═══════════════════════════════════════════════════════
// Risk
// ═══════════════════════════════════════════════════════

let _riskSeq = 0;

/**
 * @param {object} p
 * @param {string} [p.id]
 * @param {string} p.description
 * @param {"low"|"medium"|"high"|"critical"} p.level
 * @param {string} p.source        — "checklist" | "baseline" | "gate" | "manual" | "observation"
 * @param {string} [p.mitigation]
 * @param {object} [p.metadata]
 * @returns {object}
 */
export function createRisk({ id, description, level, source = "manual", mitigation = "", metadata = {} }) {
  if (!RISK_LEVEL[level.toUpperCase()]) throw new TypeError(`Invalid risk level: ${level}`);
  return {
    id: id || `risk-${++_riskSeq}`,
    description,
    level,
    source,
    mitigation,
    metadata: { ...metadata },
    timestamp: new Date().toISOString(),
    resolved: false,
    resolvedAt: null,
  };
}

// ═══════════════════════════════════════════════════════
// GateDecision
// ═══════════════════════════════════════════════════════

/**
 * @param {object} p
 * @param {"OPEN"|"CLOSED"|"WARN"} p.decision
 * @param {string[]} [p.blockers]
 * @param {string[]} [p.warnings]
 * @param {string} [p.summary]
 * @param {object} [p.checklistResult]
 * @param {object} [p.baselineResult]
 * @returns {object}
 */
export function createGateDecision({ decision, blockers = [], warnings = [], summary = "", checklistResult = null, baselineResult = null }) {
  if (!GATE_DECISION[decision]) throw new TypeError(`Invalid gate decision: ${decision}`);
  return {
    decision,
    blockers: [...blockers],
    warnings: [...warnings],
    summary,
    checklistResult,
    baselineResult,
    timestamp: new Date().toISOString(),
  };
}

// ═══════════════════════════════════════════════════════
// CertificationResult
// ═══════════════════════════════════════════════════════

/**
 * @param {object} p
 * @param {"none"|"bronze"|"silver"|"gold"|"platinum"} p.tier
 * @param {number} p.score              — 0-100
 * @param {string[]} [p.passedCriteria]
 * @param {string[]} [p.failedCriteria]
 * @param {string} [p.recommendation]
 * @returns {object}
 */
export function createCertificationResult({ tier, score, passedCriteria = [], failedCriteria = [], recommendation = "" }) {
  if (!CERTIFICATION_TIER[tier.toUpperCase()]) throw new TypeError(`Invalid certification tier: ${tier}`);
  return {
    tier,
    score: Math.max(0, Math.min(100, Math.round(score))),
    passedCriteria: [...passedCriteria],
    failedCriteria: [...failedCriteria],
    recommendation,
    timestamp: new Date().toISOString(),
  };
}

// ═══════════════════════════════════════════════════════
// Observation
// ═══════════════════════════════════════════════════════

let _obsSeq = 0;

/**
 * @param {object} p
 * @param {string} [p.id]
 * @param {string} p.taskId
 * @param {string} p.stage      — pipeline stage where observed
 * @param {string} p.message
 * @param {"info"|"warn"|"error"} p.severity
 * @param {object} [p.data]
 * @returns {object}
 */
export function createObservation({ id, taskId, stage, message, severity = "info", data = {} }) {
  return {
    id: id || `obs-${++_obsSeq}`,
    taskId,
    stage,
    message,
    severity,
    data: { ...data },
    timestamp: new Date().toISOString(),
  };
}

// ═══════════════════════════════════════════════════════
// Metric
// ═══════════════════════════════════════════════════════

let _metricSeq = 0;

/**
 * @param {object} p
 * @param {string} [p.id]
 * @param {string} p.taskId
 * @param {string} p.name
 * @param {number} p.value
 * @param {string} p.unit
 * @param {object} [p.tags]
 * @returns {object}
 */
export function createMetric({ id, taskId, name, value, unit = "", tags = {} }) {
  return {
    id: id || `metric-${++_metricSeq}`,
    taskId,
    name,
    value,
    unit,
    tags: { ...tags },
    timestamp: new Date().toISOString(),
  };
}

// ═══════════════════════════════════════════════════════
// TaskResult（最终结果聚合）
// ═══════════════════════════════════════════════════════

/**
 * @param {object} p
 * @returns {object}
 */
export function createTaskResult({
  taskId, status,
  executedSteps = [], changedFiles = [], artifactIds = [],
  checklistResult = null, baselineComparison = null,
  gateDecision = null, certification = null,
  risks = [], observations = [], metrics = [],
  durationMs = 0, recommendedNextAction = "",
}) {
  return {
    taskId, status,
    executedSteps, changedFiles, artifactIds,
    checklistResult, baselineComparison,
    gateDecision, certification,
    risks, observations, metrics,
    durationMs,
    recommendedNextAction,
    timestamp: new Date().toISOString(),
  };
}
