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

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

  /** Upsert progress for a user+material pair. */
  async upsertProgress(data: {
    userId: string;
    readingTargetType: string;
    materialId: string;
    knowledgeBaseId?: string | null;
    lastPosition?: any;
    lastProgress?: number;
    activeSecondsDelta: number;
    status?: string;
  }) {
    const existing = await this.prisma.materialReadingProgress.findUnique({
      where: {
        userId_materialId: { userId: data.userId, materialId: data.materialId },
      },
    });

    const isNew = !existing || !existing.firstOpenedAt;

    return this.prisma.materialReadingProgress.upsert({
      where: {
        userId_materialId: { userId: data.userId, materialId: data.materialId },
      },
      create: {
        userId: data.userId,
        readingTargetType: data.readingTargetType,
        materialId: data.materialId,
        knowledgeBaseId: data.knowledgeBaseId ?? null,
        lastPosition: data.lastPosition ?? undefined,
        lastProgress: data.lastProgress ?? undefined,
        totalActiveSeconds: data.activeSecondsDelta,
        sessionCount: 1,
        status: 'reading',
        firstOpenedAt: new Date(),
        lastOpenedAt: new Date(),
      },
      update: {
        totalActiveSeconds: { increment: data.activeSecondsDelta },
        sessionCount: isNew ? { increment: 1 } : undefined,
        lastPosition: data.lastPosition ?? undefined,
        lastProgress: data.lastProgress ?? undefined,
        status: data.status ?? existing?.status ?? 'reading',
        lastOpenedAt: new Date(),
        lastReadAt: new Date(),
      },
    });
  }

  /** M8: Upsert from reading event (within transaction). */
  async upsertFromReadingEvent(tx: any, data: {
    userId: string;
    readingTargetType: string;
    materialId: string;
    knowledgeBaseId: string | null;
    eventType: string;
    activeSecondsDelta: number;
    position: any | null;
    isNewSession: boolean;
  }) {
    const existing = await tx.materialReadingProgress.findUnique({
      where: { userId_materialId: { userId: data.userId, materialId: data.materialId } },
    });

    const isNew = !existing || !existing.firstOpenedAt;
    const isMarkedRead = data.eventType === 'marked_as_read';
    const isClosed = data.eventType === 'material_closed';

    const update: any = {};
    if (data.activeSecondsDelta > 0) {
      update.totalActiveSeconds = { increment: data.activeSecondsDelta };
    }
    if (data.position) {
      update.lastPosition = data.position;
      update.lastProgress = this.extractProgress(data.position);
    }
    // MaterialClosed without position: don't overwrite lastPosition
    if (isMarkedRead) {
      update.isMarkedRead = true;
      update.markedReadAt = new Date();
      update.status = 'read';
      update.lastProgress = 1.0;
    } else if (isClosed) {
      update.status = 'read';
    } else if (isNew) {
      update.status = 'reading';
    }
    update.lastReadAt = new Date();
    if (isNew) {
      update.firstOpenedAt = new Date();
    }
    if (data.isNewSession) {
      update.sessionCount = { increment: 1 };
      update.lastOpenedAt = new Date();
    }

    if (isNew) {
      // create() 不支持 { increment: N } 语法，需转为普通值
      const createData: any = {
        userId: data.userId,
        readingTargetType: data.readingTargetType,
        materialId: data.materialId,
        knowledgeBaseId: data.knowledgeBaseId,
      };
      for (const [key, value] of Object.entries(update)) {
        if (value && typeof value === 'object' && 'increment' in value) {
          createData[key] = (value as any).increment;
        } else {
          createData[key] = value;
        }
      }
      return tx.materialReadingProgress.create({ data: createData });
    }

    return tx.materialReadingProgress.update({
      where: { userId_materialId: { userId: data.userId, materialId: data.materialId } },
      data: update,
    });
  }

  private extractProgress(position: any): number | null {
    if (!position) return null;
    // Try common progress field names
    if (typeof position.overallProgress === 'number') return position.overallProgress;
    if (typeof position.scrollProgress === 'number') return position.scrollProgress;
    if (typeof position.chapterProgress === 'number') return position.chapterProgress;
    return null;
  }

  /** Get progress for a specific material. */
  async getProgress(userId: string, materialId: string) {
    return this.prisma.materialReadingProgress.findUnique({
      where: { userId_materialId: { userId, materialId } },
    });
  }
}
