import { Injectable, Logger, Optional } from '@nestjs/common';
import type { Prisma } from '@prisma/client';
import {
  ResultProjector,
  ProjectionContext,
  ArtifactReference,
} from './result-projector.interface';
import { AiJobCreationService } from './ai-job-creation.service';
import { ReviewCardGenerationSnapshotBuilder } from './review-card-generation-snapshot-builder';
import type { ReviewCardGenerationSnapshotInput } from './review-card-generation-snapshot-builder';
import { FeatureFlagService } from '../config/feature-flag.service';
import { EventBusService } from '../../common/event-bus/event-bus.service';
import { BaseDomainEvent } from '../../common/events/base-domain.event';

/**
 * M-AI-05-04 / M-AI-06-06: Feynman Result Projector
 *
 * 将验证后的 Feynman AI 输出原子投影到现有业务模型。
 *
 * 契约依据：
 *   - docs/architecture/m-ai-05-feynman-migration-contract.md §11, §13
 *   - docs/architecture/m-ai-06-review-card-child-job-contract.md §2, §7
 *
 * 在 Prisma Transaction 内与 markSucceeded 共享事务：
 *   1. AiAnalysisResult — 分析结果（upsert by deterministic ID fe_<jobId>）
 *   2. FocusItem — 每个 weakness 字符串创建一条（事务内 findFirst + create 幂等）
 *   3. AiJobArtifact — 上述每个实体一条引用
 *   4. ReviewCard Child Job（child_job 模式）— 同一事务创建 Child Job + Snapshot + Outbox
 *
 * M-AI-06-06: ReviewCard 生成路由
 *   - FEYNMAN_REVIEW_CARD_MODE = 'child_job' → 事务内创建 review_card_generation Child Job
 *   - FEYNMAN_REVIEW_CARD_MODE = 'legacy_event'（默认）→ 事务成功后发布 ai.analysis.completed
 *
 * 幂等策略：
 *   - 入口幂等：检查已有 Artifact → 直接返回
 *   - AiAnalysisResult：deterministic ID（fe_<jobId>）+ upsert
 *   - FocusItem：事务内 findFirst + create（userId + title + source 去重）
 *   - Child Job：idempotencyKey = review-card:feynman:<parentJobId>（Db 级 @@unique）
 *
 * 与旧链路的差异（Bug 修复）：
 *   - 旧链路 knowledgeBaseId 永远为 'unknown'（result.knowledgeBaseId 不存在于 Feynman Schema）
 *   - 本 Projector 从 Snapshot 读取真实 knowledgeBaseId + knowledgeItemId
 */

const FLAG_REVIEW_CARD_MODE = 'FEYNMAN_REVIEW_CARD_MODE';

/** Legacy 事件类型（与 AiAnalysisWorker 一致） */
class AIAnalysisCompleted extends BaseDomainEvent {
  eventType = 'ai.analysis.completed';
  constructor(public readonly payload: Record<string, any>) { super(); }
}

@Injectable()
export class FeynmanProjector implements ResultProjector {
  readonly key = 'feynman_evaluation_projector';
  private readonly logger = new Logger(FeynmanProjector.name);

  constructor(
    private readonly creationService: AiJobCreationService,
    private readonly rcSnapshotBuilder: ReviewCardGenerationSnapshotBuilder,
    private readonly featureFlag: FeatureFlagService,
    @Optional() private readonly eventBus?: EventBusService,
  ) {}

  async project(
    tx: Prisma.TransactionClient,
    context: ProjectionContext,
  ): Promise<ArtifactReference[]> {
    const { job, validatedOutput, snapshot } = context;
    let ordinal = 0;

    // ── 入口幂等：已有 Artifact → 直接返回 ──
    const existingArtifacts = await tx.aiJobArtifact.findMany({
      where: { jobId: job.id },
      orderBy: { ordinal: 'asc' },
    });
    if (existingArtifacts.length > 0) {
      this.logger.log(
        `Feynman Projector: returning ${existingArtifacts.length} existing artifact(s) for job=${job.id}`,
      );
      return existingArtifacts.map((a) => ({
        artifactType: a.artifactType,
        artifactId: a.artifactId,
        ordinal: a.ordinal,
      }));
    }

    const artifacts: ArtifactReference[] = [];

    // ═════════════════════════════════════════════════════════
    // 1. AiAnalysisResult（Feynman 评估结果）
    //    使用 deterministic ID 实现 upsert（无 Migration 下的幂等方案）
    // ═════════════════════════════════════════════════════════

    const resultId = deterministicResultId(job.id);
    const resultData = {
      id: resultId,
      userId: job.userId,
      jobId: job.id,
      summary: validatedOutput.summary ?? '',
      masteryScore: validatedOutput.score ?? null,
      strengths: (validatedOutput.strengths ?? []) as any,
      weaknesses: (validatedOutput.weaknesses ?? []) as any,
      suggestions: (validatedOutput.suggestions ?? []) as any,
      nextActions: null as any,
      rawResult: validatedOutput as any,
    };

    await tx.aiAnalysisResult.upsert({
      where: { id: resultId },
      create: resultData,
      update: {
        summary: resultData.summary,
        masteryScore: resultData.masteryScore,
        strengths: resultData.strengths,
        weaknesses: resultData.weaknesses,
        suggestions: resultData.suggestions,
        rawResult: resultData.rawResult,
      },
    });

    await tx.aiJobArtifact.create({
      data: {
        jobId: job.id,
        artifactType: 'AiAnalysisResult',
        artifactId: resultId,
        ordinal: ordinal++,
        metadata: { score: validatedOutput.score } as any,
      },
    });
    artifacts.push({
      artifactType: 'AiAnalysisResult',
      artifactId: resultId,
      ordinal: ordinal - 1,
    });

    this.logger.log(
      `Feynman Projector: AiAnalysisResult ${resultId} written for job=${job.id}`,
    );

    // ═════════════════════════════════════════════════════════
    // 2. FocusItem（从 weaknesses 字符串创建）
    //    契约 §11：每个 weakness 字符串 → 1 个 FocusItem
    //    修复 Legacy bug：knowledgeBaseId 从 Snapshot 读取（不再为 'unknown'）
    //    幂等：相同 userId + title + source 不重复创建
    // ═════════════════════════════════════════════════════════

    const weaknesses: string[] = validatedOutput.weaknesses ?? [];
    const knowledgeBaseId = snapshot?.snapshot?.knowledgeBaseId ?? 'unknown';
    const knowledgeItemId = snapshot?.snapshot?.knowledgeItemId ?? null;

    for (const title of weaknesses) {
      if (!title || typeof title !== 'string' || title.trim().length === 0) continue;

      // 幂等：同一 userId + title + source 不重复创建
      const existingFi = await tx.focusItem.findFirst({
        where: {
          userId: job.userId,
          title: title.trim(),
          source: 'ai-analysis',
        },
      });

      if (existingFi) {
        // 已存在 → 只补写 Artifact（如缺失）
        await upsertArtifact(tx, job.id, 'FocusItem', existingFi.id, ordinal);
        artifacts.push({
          artifactType: 'FocusItem',
          artifactId: existingFi.id,
          ordinal: ordinal++,
        });
        continue;
      }

      const record = await tx.focusItem.create({
        data: {
          userId: job.userId,
          title: title.trim(),
          reason: '',
          suggestion: '',
          priority: 'normal',
          status: 'open',
          source: 'ai-analysis',
          knowledgeBaseId,                     // ★ 修复：从 Snapshot 读取
          knowledgeItemId: knowledgeItemId,    // ★ 新增：Legacy 未设置
        },
      });

      await upsertArtifact(tx, job.id, 'FocusItem', record.id, ordinal);
      artifacts.push({
        artifactType: 'FocusItem',
        artifactId: record.id,
        ordinal: ordinal++,
      });
    }

    if (weaknesses.length > 0) {
      this.logger.log(
        `Feynman Projector: ${weaknesses.filter(w => w && typeof w === 'string' && w.trim().length > 0).length} FocusItem(s) written for job=${job.id}`,
      );
    }

    // ═════════════════════════════════════════════════════════
    // 3. ReviewCard 生成路由（M-AI-06-06）
    //    FEYNMAN_REVIEW_CARD_MODE = child_job | legacy_event
    // ═════════════════════════════════════════════════════════

    await this.routeReviewCardGeneration(tx, job, validatedOutput, snapshot, artifacts);

    // ═════════════════════════════════════════════════════════
    // 完成
    // ═════════════════════════════════════════════════════════

    this.logger.log(
      `Feynman Projector: ${artifacts.length} artifact(s) total for job=${job.id}`,
    );
    return artifacts;
  }

  // ── ReviewCard 生成路由（M-AI-06-06） ──

  /**
   * 根据 FEYNMAN_REVIEW_CARD_MODE 决定 ReviewCard 生成方式。
   *
   * - child_job：事务内创建 review_card_generation Child Job
   * - legacy_event（默认）：事务成功后发布 ai.analysis.completed 事件
   */
  private async routeReviewCardGeneration(
    tx: Prisma.TransactionClient,
    job: { id: string; userId: string },
    validatedOutput: Record<string, any>,
    snapshot: any,
    artifacts: ArtifactReference[],
  ): Promise<void> {
    let mode: string;
    try {
      const enabled = await this.featureFlag.isEnabled(FLAG_REVIEW_CARD_MODE, job.userId);
      mode = enabled ? 'child_job' : 'legacy_event';
      this.logger.log(
        `FEYNMAN_REVIEW_CARD_MODE=${mode} for userId=${job.userId} job=${job.id}`,
      );
    } catch (err: any) {
      // Flag 查询失败 → 安全回退到 legacy_event
      this.logger.warn(
        `FeatureFlag query failed, falling back to legacy_event: ${err.message}`,
      );
      mode = 'legacy_event';
    }

    if (mode === 'child_job') {
      await this.createReviewCardChildJob(tx, job, validatedOutput, snapshot, artifacts);
    } else {
      // legacy_event：事件在事务成功后由调用方（ProjectionExecutor）发布不在此处，
      // 但为了兼容性，在投影完成后记录日志。
      // ★ 事件发布由 Engine 在 PROJECT 成功后处理。
      this.logger.log(
        `legacy_event mode: ReviewCard will be generated via EventBus for job=${job.id}`,
      );
    }
  }

  /**
   * 在同一事务中创建 ReviewCard Generation Child Job。
   *
   * 原子性：Child Job + Snapshot + Outbox 与 Parent Projection 在同一事务。
   * 幂等：idempotencyKey = review-card:feynman:<parentJobId>，Db 级 @@unique 保证。
   */
  private async createReviewCardChildJob(
    tx: Prisma.TransactionClient,
    job: { id: string; userId: string },
    validatedOutput: Record<string, any>,
    snapshot: any,
    artifacts: ArtifactReference[],
  ): Promise<void> {
    const sourceResultId = deterministicResultId(job.id);

    // 1. 构建 Child Snapshot（事务内，数据均来自已验证的 Feynman 输出）
    const rcInput: ReviewCardGenerationSnapshotInput = {
      userId: job.userId,
      parentJobId: job.id,
      sourceResultId,
      knowledgeItemId: snapshot?.snapshot?.knowledgeItemId ?? null,
      knowledgeBaseId: snapshot?.snapshot?.knowledgeBaseId ?? 'unknown',
      summary: validatedOutput.summary ?? '',
      strengths: (validatedOutput.strengths ?? []) as string[],
      weaknesses: (validatedOutput.weaknesses ?? []) as string[],
    };

    const rcSnapshot = this.rcSnapshotBuilder.build(rcInput);

    // 2. 在外部事务中创建 Child Job（复用 createInTransaction）
    const childJob = await this.creationService.createInTransaction(tx, {
      userId: job.userId,
      jobType: 'review_card_generation',
      triggerType: 'parent_job',
      targetType: 'ai_analysis_result',
      targetId: sourceResultId,
      parentJobId: job.id,
      idempotencyKey: `review-card:feynman:${job.id}`,
      retrySnapshotContent: rcSnapshot as unknown as Record<string, unknown>,
    });

    // 3. 记录 Child Job Artifact（父 Job 的可观测性关联）
    await upsertArtifact(
      tx,
      job.id,
      'ReviewCardChildJob',
      childJob.id,
      artifacts.length,
    );
    artifacts.push({
      artifactType: 'ReviewCardChildJob',
      artifactId: childJob.id,
      ordinal: artifacts.length,
    });

    this.logger.log(
      `ReviewCard Child Job created: childJobId=${childJob.id} ` +
      `parentJobId=${job.id} sourceResultId=${sourceResultId} ` +
      `cardCount=${rcSnapshot.snapshot.cardCount} ` +
      `idempotencyKey=review-card:feynman:${job.id}`,
    );
  }
}

// ── Helpers ──

/** 从 jobId 派生确定性 AiAnalysisResult ID */
function deterministicResultId(jobId: string): string {
  // jobId 格式: cuid (25 chars)，取前 23 字符 + "fe_" 前缀
  return `fe_${jobId.substring(0, 23)}`;
}

/** 幂等写入 Artifact（jobId + artifactType + artifactId 唯一约束） */
async function upsertArtifact(
  tx: Prisma.TransactionClient,
  jobId: string,
  artifactType: string,
  artifactId: string,
  ordinal: number,
): Promise<void> {
  try {
    await tx.aiJobArtifact.create({
      data: { jobId, artifactType, artifactId, ordinal },
    });
  } catch (err: any) {
    // P2002: 唯一约束冲突 → 已存在，幂等跳过
    if (err?.code === 'P2002') {
      return;
    }
    throw err;
  }
}
