import { Injectable } from '@nestjs/common';
import { IllegalStateTransitionError } from './ai-job.errors';

/**
 * M-AI-03-03: AiJob 统一状态机
 *
 * 定义合法状态迁移，所有 lifecycleStatus 变更必须经过此验证。
 *
 * 状态机（ADR-003 §1.1）：
 *   queued → running → succeeded / failed / cancelled
 *   queued → cancelled（直接取消，无需先 running）
 *
 * cancel_requested 不是独立状态 — 它是 running 状态上的信号字段（cancelRequestedAt）。
 */

export const LIFECYCLE_STATUSES = [
  'queued',
  'running',
  'succeeded',
  'failed',
  'cancelled',
] as const;

export type LifecycleStatus = (typeof LIFECYCLE_STATUSES)[number];

export const TERMINAL_STATUSES: ReadonlySet<LifecycleStatus> = new Set([
  'succeeded',
  'failed',
  'cancelled',
]);

/** 合法状态迁移（from → to） */
const ALLOWED_TRANSITIONS: Record<LifecycleStatus, ReadonlySet<LifecycleStatus>> = {
  queued:     new Set<LifecycleStatus>(['running', 'cancelled']),
  running:    new Set<LifecycleStatus>(['succeeded', 'failed', 'cancelled']),
  succeeded:  new Set<LifecycleStatus>([]), // 终态
  failed:     new Set<LifecycleStatus>([]), // 终态
  cancelled:  new Set<LifecycleStatus>([]), // 终态
};

/**
 * ── M-AI-02-10 Legacy status Shadow Write ──
 *
 * 新 lifecycleStatus → 旧 status 列映射。
 * 双向均可查询：
 *   - STATUS_TO_LIFECYCLE: 旧 → 新（ai-analysis.repository.ts 已在用）
 *   - LIFECYCLE_TO_STATUS: 新 → 旧（本 Repository Shadow Write 使用）
 */
export const LIFECYCLE_TO_STATUS: Record<LifecycleStatus, string> = {
  queued:     'pending',
  running:    'processing',
  succeeded:  'completed',
  failed:     'failed',
  cancelled:  'failed', // cancelled 在旧 status 中不存在，映射为 failed + errorCode='CANCELLED'
};

export const STATUS_TO_LIFECYCLE: Record<string, LifecycleStatus> = {
  pending:            'queued',
  processing:         'running',
  completed:          'succeeded',
  failed:             'failed',
  cancelled:          'cancelled',
  cancel_requested:   'cancelled',
};

@Injectable()
export class AiJobStateMachine {
  /**
   * 校验 from → to 是否为合法迁移。
   * 合法 → 无返回值；非法 → 抛出 IllegalStateTransitionError。
   */
  validate(from: LifecycleStatus, to: LifecycleStatus): void {
    const allowed = ALLOWED_TRANSITIONS[from];
    if (!allowed || !allowed.has(to)) {
      throw new IllegalStateTransitionError('unknown', from, to);
    }
  }

  /**
   * 校验带 jobId 的迁移。提供更精确的错误信息。
   */
  validateForJob(jobId: string, from: LifecycleStatus, to: LifecycleStatus): void {
    const allowed = ALLOWED_TRANSITIONS[from];
    if (!allowed || !allowed.has(to)) {
      throw new IllegalStateTransitionError(jobId, from, to);
    }
  }

  /** 是否为终态 */
  isTerminal(status: LifecycleStatus): boolean {
    return TERMINAL_STATUSES.has(status);
  }

  /**
   * 对于从数据库读取的状态字符串，校验并转换为类型化状态。
   */
  parse(status: string | null | undefined): LifecycleStatus {
    if (!status) return 'queued';
    if ((LIFECYCLE_STATUSES as readonly string[]).includes(status)) {
      return status as LifecycleStatus;
    }
    throw new IllegalStateTransitionError('unknown', status, 'any');
  }
}
