import { Injectable } from '@nestjs/common';
import { PrismaService } from '../../infrastructure/database/prisma.service';

export const LEARNING_RECORD_TYPES = [
  'reading',
  'read_completed',
  'review',
  'quiz',
  'chat',
  'note',
  'manual',
] as const;

const VALID_RECORD_TYPES = new Set<string>(LEARNING_RECORD_TYPES);

@Injectable()
export class LearningRecordService {
  constructor(private readonly prisma: PrismaService) {}

  async create(data: {
    userId: string;
    recordType: string;
    title: string;
    description?: string;
    sessionId?: string;
    durationSeconds?: number;
    occurredAt?: Date;
    metadata?: Record<string, any>;
  }) {
    if (!VALID_RECORD_TYPES.has(data.recordType)) {
      throw new Error(`Invalid recordType: ${data.recordType}. Must be one of: ${LEARNING_RECORD_TYPES.join(', ')}`);
    }
    return this.prisma.learningRecord.create({
      data: {
        userId: data.userId,
        sessionId: data.sessionId ?? null,
        recordType: data.recordType,
        title: data.title,
        description: data.description ?? null,
        durationSeconds: data.durationSeconds ?? 0,
        occurredAt: data.occurredAt ?? new Date(),
        metadata: data.metadata ?? undefined,
      },
    });
  }

  async findByUser(
    userId: string,
    opts: { page?: number; limit?: number; recordType?: string; cursor?: string } = {},
  ) {
    const { page = 1, limit = 20, recordType, cursor } = opts;
    return this.prisma.learningRecord.findMany({
      where: {
        userId,
        ...(recordType ? { recordType } : {}),
      },
      orderBy: { occurredAt: 'desc' },
      ...(cursor
        ? { cursor: { id: cursor }, skip: 1 }
        : { skip: (page - 1) * limit }),
      take: limit,
    });
  }

  async findBySessionId(sessionId: string) {
    return this.prisma.learningRecord.findMany({
      where: { sessionId },
      orderBy: { occurredAt: 'asc' },
    });
  }

  async deleteById(id: string, userId: string) {
    const record = await this.prisma.learningRecord.findUnique({ where: { id } });
    if (!record) throw new Error('LearningRecord not found');
    if (record.userId !== userId) throw new Error('Access denied');
    return this.prisma.learningRecord.delete({ where: { id } });
  }

  /** M8: Create a reading record from a processed event (within transaction). */
  async createReadingRecordTx(tx: any, data: {
    userId: string;
    sessionId?: string;
    materialId: string;
    readingTargetType: string;
    knowledgeBaseId?: string | null;
    title: string;
    totalActiveSeconds?: number;
    lastPosition?: any;
    occurredAt: Date;
  }) {
    if (!VALID_RECORD_TYPES.has('reading')) {
      throw new Error('Invalid recordType');
    }
    const positionSnapshot = data.lastPosition
      ? { type: data.lastPosition.type, progress: data.lastPosition.progressValue ?? null }
      : null;

    return tx.learningRecord.create({
      data: {
        userId: data.userId,
        sessionId: data.sessionId ?? null,
        recordType: 'reading',
        title: data.title,
        durationSeconds: data.totalActiveSeconds ?? 0,
        occurredAt: data.occurredAt,
        metadata: {
          materialId: data.materialId,
          readingTargetType: data.readingTargetType,
          knowledgeBaseId: data.knowledgeBaseId ?? null,
          totalActiveSeconds: data.totalActiveSeconds,
          lastPosition: positionSnapshot,
        },
      },
    });
  }

  /** M8: Create a reading record from a processed event (outside transaction). */
  async createReadingRecord(data: {
    userId: string;
    sessionId?: string;
    materialId: string;
    readingTargetType: string;
    knowledgeBaseId?: string | null;
    title: string;
    totalActiveSeconds?: number;
    lastPosition?: any;
    occurredAt: Date;
  }) {
    const positionSnapshot = data.lastPosition
      ? { type: data.lastPosition.type, progress: data.lastPosition.progressValue ?? null }
      : null;

    return this.create({
      userId: data.userId,
      recordType: 'reading',
      title: data.title,
      sessionId: data.sessionId,
      durationSeconds: data.totalActiveSeconds ?? 0,
      occurredAt: data.occurredAt,
      metadata: {
        materialId: data.materialId,
        readingTargetType: data.readingTargetType,
        knowledgeBaseId: data.knowledgeBaseId ?? null,
        totalActiveSeconds: data.totalActiveSeconds,
        lastPosition: positionSnapshot,
      },
    });
  }
}
