import { Controller, Get, Param, Query, Req, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
import { PrismaService } from '../../infrastructure/database/prisma.service';
import { LearningActivityRepository } from '../learning-activity/learning-activity.repository';
import { LearningRecordService } from '../learning-record/learning-record.service';
import { MaterialReadingProgressService } from '../material-reading-progress/material-reading-progress.service';
import { ReadingEventProcessorService } from '../reading-event/reading-event-processor.service';

@Controller()
@UseGuards(JwtAuthGuard)
export class ReadingController {
  constructor(
    private readonly prisma: PrismaService,
    private readonly progressSvc: MaterialReadingProgressService,
    private readonly processor: ReadingEventProcessorService,
    private readonly activityRepo: LearningActivityRepository,
    private readonly recordSvc: LearningRecordService,
  ) {}

  @Get('materials/:id/reading-progress')
  async getProgress(
    @Req() req: any,
    @Param('id') materialId: string,
    @Query('readingTargetType') targetType?: string,
  ) {
    const userId = req.user.id;

    if (targetType) {
      const access = await this.processor.validateReadingAccess(userId, targetType, materialId);
      if (!access.allowed) {
        return { status: 'not_started', reason: access.errorCode };
      }
    }

    const progress = await this.progressSvc.getProgress(userId, materialId);
    if (!progress) {
      return {
        status: 'not_started',
        lastPosition: null,
        lastProgress: null,
        totalActiveSeconds: 0,
        isMarkedRead: false,
      };
    }

    return {
      status: progress.status,
      lastPosition: progress.lastPosition,
      lastProgress: progress.lastProgress,
      totalActiveSeconds: progress.totalActiveSeconds,
      isMarkedRead: progress.isMarkedRead,
      firstOpenedAt: progress.firstOpenedAt,
      lastReadAt: progress.lastReadAt,
    };
  }

  @Get('learning/continue')
  async continueLearning(@Req() req: any) {
    const userId = req.user.id;

    const latest = await this.prisma.materialReadingProgress.findFirst({
      where: {
        userId,
        lastReadAt: { not: null },
        status: { in: ['reading', 'read'] },
      },
      orderBy: { lastReadAt: 'desc' },
    });

    if (!latest) {
      return { type: 'none' };
    }

    let title: string | null = null;
    let isAccessible = true;

    if (latest.readingTargetType === 'knowledge_source') {
      const src = await this.prisma.knowledgeSource.findUnique({
        where: { id: latest.materialId },
        select: { title: true, deletedAt: true },
      });
      if (src && !src.deletedAt) {
        title = src.title;
      } else {
        isAccessible = false;
      }
    } else if (latest.readingTargetType === 'temporary_file') {
      const mat = await this.prisma.temporaryReadingMaterial.findUnique({
        where: { id: latest.materialId },
        select: { title: true, deletedAt: true, expiresAt: true, sourceStatus: true },
      });
      if (mat && !mat.deletedAt && !mat.expiresAt && mat.sourceStatus !== 'expired') {
        title = mat.title;
      } else {
        isAccessible = false;
      }
    }

    return {
      type: isAccessible ? latest.readingTargetType : 'none',
      materialId: latest.materialId,
      title,
      lastPosition: latest.lastPosition,
      lastProgress: latest.lastProgress,
      totalActiveSeconds: latest.totalActiveSeconds,
      lastReadAt: latest.lastReadAt,
    };
  }

  @Get('learning/summary')
  async getSummary(@Req() req: any) {
    const userId = req.user.id;
    const now = new Date();
    const todayStr = now.toISOString().split('T')[0];
    const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);

    // Query recent 90 days for week/today + aggregate totals
    const from = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);
    const activities = await this.activityRepo.findByDateRange(userId, from, now);
    const allActivities = await this.activityRepo.findAll(userId);

    if (!allActivities.length) {
      return { todaySeconds: 0, weekSeconds: 0, totalSeconds: 0, activeDays: 0, sessionsCount: 0, materialsReadCount: 0, markedReadCount: 0, dailyAverageSeconds: 0 };
    }

    let todaySeconds = 0, weekSeconds = 0, recentSeconds = 0;
    let totalSeconds = 0, activeDays = 0, sessionsCount = 0, materialsReadCount = 0, markedReadCount = 0;

    for (const a of allActivities) {
      totalSeconds += a.readingSeconds;
      sessionsCount += a.sessionsCount;
      materialsReadCount += a.materialsReadCount;
      markedReadCount += a.markedReadCount;
      if (a.readingSeconds > 0) activeDays++;
    }

    for (const a of activities) {
      const dateStr = a.activityDate instanceof Date ? a.activityDate.toISOString().split('T')[0] : String(a.activityDate).split('T')[0];
      if (dateStr === todayStr) todaySeconds += a.readingSeconds;
      const actDate = a.activityDate instanceof Date ? a.activityDate : new Date(a.activityDate);
      if (actDate >= weekAgo) weekSeconds += a.readingSeconds;
    }

    return {
      todaySeconds, weekSeconds, totalSeconds, activeDays,
      sessionsCount, materialsReadCount, markedReadCount,
      dailyAverageSeconds: activeDays > 0 ? Math.round(totalSeconds / activeDays) : 0,
    };
  }

  @Get('learning/trend')
  async getTrend(@Req() req: any, @Query('days') daysStr?: string) {
    const userId = req.user.id;
    const days = Math.min(Number(daysStr ?? 7) || 7, 90);
    const now = new Date();
    const from = new Date(now.getTime() - days * 24 * 60 * 60 * 1000);

    const activities = await this.activityRepo.findByDateRange(userId, from, now);
    const dataMap = new Map<string, number>();
    for (const a of activities) {
      const ds = a.activityDate instanceof Date ? a.activityDate.toISOString().split('T')[0] : String(a.activityDate).split('T')[0];
      dataMap.set(ds, (dataMap.get(ds) ?? 0) + a.readingSeconds);
    }

    const series: Array<{ date: string; value: number }> = [];
    for (let i = days - 1; i >= 0; i--) {
      const d = new Date(now.getTime() - i * 24 * 60 * 60 * 1000);
      const ds = d.toISOString().split('T')[0];
      series.push({ date: ds, value: dataMap.get(ds) ?? 0 });
    }

    return { days, series };
  }

  @Get('learning/records')
  async getRecords(
    @Req() req: any,
    @Query('cursor') cursor?: string,
    @Query('limit') limitStr?: string,
    @Query('type') recordType?: string,
  ) {
    const userId = req.user.id;
    const limit = Math.min(Number(limitStr ?? 20) || 20, 50);

    const records = await this.recordSvc.findByUser(userId, {
      limit: limit + 1,
      recordType,
      cursor: cursor ?? undefined,
    });

    let nextCursor: string | null = null;
    if (records.length > limit) {
      nextCursor = records[limit]?.id ?? null;
      records.length = limit;
    }

    const items = records.map(r => ({
      id: r.id,
      recordType: r.recordType,
      title: r.title,
      description: r.description,
      durationSeconds: r.durationSeconds,
      occurredAt: r.occurredAt,
      metadata: r.metadata,
      createdAt: r.createdAt,
    }));

    return { items, nextCursor };
  }
}
