import { Controller, Get, Param, Post, Query, UseGuards } from '@nestjs/common';
import { AdminAuthGuard } from '../../common/guards/admin-auth.guard';
import { PrismaService } from '../../infrastructure/database/prisma.service';

@Controller('admin/learning')
@UseGuards(AdminAuthGuard)
export class AdminReadingController {
  constructor(private readonly prisma: PrismaService) {}

  // ── Dashboard ──

  @Get('dashboard')
  async getDashboard() {
    const now = new Date();
    const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());

    const [totalEvents, todayEvents, failedEvents, duplicateEvents,
           activeSessions, interruptedSessions, completedSessions, totalSessions,
           activeUsers, totalUsers,
           totalRead, totalMarkedRead] = await Promise.all([
      this.prisma.readingEvent.count(),
      this.prisma.readingEvent.count({ where: { createdAt: { gte: todayStart } } }),
      this.prisma.readingEvent.count({ where: { status: 'failed' } }),
      this.prisma.readingEvent.count({ where: { status: 'duplicate' } }),
      this.prisma.learningSession.count({ where: { status: 'active' } }),
      this.prisma.learningSession.count({ where: { status: 'interrupted' } }),
      this.prisma.learningSession.count({ where: { status: 'completed' } }),
      this.prisma.learningSession.count(),
      this.prisma.dailyLearningActivity.count({ where: { activityDate: { gte: todayStart } } }),
      this.prisma.dailyLearningActivity.groupBy({ by: ['userId'], _count: true }).then(r => r.length),
      this.prisma.materialReadingProgress.count({ where: { status: { not: 'not_started' } } }),
      this.prisma.materialReadingProgress.count({ where: { isMarkedRead: true } }),
    ]);

    return {
      overview: { totalEvents, todayEvents, failedEvents, duplicateEvents },
      sessions: { active: activeSessions, interrupted: interruptedSessions, completed: completedSessions, total: totalSessions },
      users: { activeToday: activeUsers, totalWithEvents: totalUsers },
      materials: { totalRead, totalMarkedRead },
    };
  }

  // ── ReadingEvent ──

  @Get('reading-events')
  async listEvents(@Query() q: any) {
    const page = Math.max(1, Number(q.page) || 1);
    const limit = Math.min(100, Math.max(1, Number(q.limit) || 20));
    const where: any = {};
    if (q.userId) where.userId = q.userId;
    if (q.materialId) where.materialId = q.materialId;
    if (q.status) where.status = q.status;
    if (q.eventType) where.eventType = q.eventType;

    const [items, total] = await Promise.all([
      this.prisma.readingEvent.findMany({ where, orderBy: { createdAt: 'desc' }, skip: (page - 1) * limit, take: limit }),
      this.prisma.readingEvent.count({ where }),
    ]);
    return { items, total, page, limit };
  }

  @Get('reading-events/failed')
  async listFailedEvents(@Query() q: any) {
    const page = Math.max(1, Number(q.page) || 1);
    const limit = Math.min(100, Math.max(1, Number(q.limit) || 20));
    const where: any = { status: { in: ['failed', 'duplicate'] } };

    const [items, total] = await Promise.all([
      this.prisma.readingEvent.findMany({ where, orderBy: { createdAt: 'desc' }, skip: (page - 1) * limit, take: limit }),
      this.prisma.readingEvent.count({ where }),
    ]);
    return { items, total, page, limit };
  }

  @Get('reading-events/:id')
  async getEvent(@Param('id') id: string) {
    return this.prisma.readingEvent.findUnique({ where: { id } });
  }

  // ── LearningSession ──

  @Get('sessions')
  async listSessions(@Query() q: any) {
    const page = Math.max(1, Number(q.page) || 1);
    const limit = Math.min(100, Math.max(1, Number(q.limit) || 20));
    const where: any = {};
    if (q.userId) where.userId = q.userId;
    if (q.status) where.status = q.status;
    if (q.materialId) where.materialId = q.materialId;

    const [items, total] = await Promise.all([
      this.prisma.learningSession.findMany({ where, orderBy: { startedAt: 'desc' }, skip: (page - 1) * limit, take: limit }),
      this.prisma.learningSession.count({ where }),
    ]);
    return { items, total, page, limit };
  }

  @Get('sessions/interrupted')
  async listInterruptedSessions(@Query() q: any) {
    const page = Math.max(1, Number(q.page) || 1);
    const limit = Math.min(100, Math.max(1, Number(q.limit) || 20));
    const where: any = { status: 'interrupted' };

    const [items, total] = await Promise.all([
      this.prisma.learningSession.findMany({ where, orderBy: { updatedAt: 'desc' }, skip: (page - 1) * limit, take: limit }),
      this.prisma.learningSession.count({ where }),
    ]);
    return { items, total, page, limit };
  }

  @Get('sessions/:id')
  async getSession(@Param('id') id: string) {
    return this.prisma.learningSession.findUnique({ where: { id } });
  }

  // ── MaterialReadingProgress ──

  @Get('progress')
  async listProgress(@Query() q: any) {
    const page = Math.max(1, Number(q.page) || 1);
    const limit = Math.min(100, Math.max(1, Number(q.limit) || 20));
    const where: any = {};
    if (q.userId) where.userId = q.userId;
    if (q.materialId) where.materialId = q.materialId;
    if (q.status) where.status = q.status;

    const [items, total] = await Promise.all([
      this.prisma.materialReadingProgress.findMany({ where, orderBy: { lastReadAt: 'desc' }, skip: (page - 1) * limit, take: limit }),
      this.prisma.materialReadingProgress.count({ where }),
    ]);
    return { items, total, page, limit };
  }

  @Get('progress/:id')
  async getProgress(@Param('id') id: string) {
    return this.prisma.materialReadingProgress.findUnique({ where: { id } });
  }

  // ── DailyLearningActivity ──

  @Get('daily-activities')
  async listDailyActivities(@Query() q: any) {
    const page = Math.max(1, Number(q.page) || 1);
    const limit = Math.min(100, Math.max(1, Number(q.limit) || 20));
    const where: any = {};
    if (q.userId) where.userId = q.userId;

    const [items, total] = await Promise.all([
      this.prisma.dailyLearningActivity.findMany({ where, orderBy: { activityDate: 'desc' }, skip: (page - 1) * limit, take: limit }),
      this.prisma.dailyLearningActivity.count({ where }),
    ]);
    return { items, total, page, limit };
  }

  // ── LearningRecord ──

  @Get('records')
  async listRecords(@Query() q: any) {
    const page = Math.max(1, Number(q.page) || 1);
    const limit = Math.min(100, Math.max(1, Number(q.limit) || 20));
    const where: any = {};
    if (q.userId) where.userId = q.userId;

    const [items, total] = await Promise.all([
      this.prisma.learningRecord.findMany({ where, orderBy: { occurredAt: 'desc' }, skip: (page - 1) * limit, take: limit }),
      this.prisma.learningRecord.count({ where }),
    ]);
    return { items, total, page, limit };
  }

  @Get('records/:id')
  async getRecord(@Param('id') id: string) {
    return this.prisma.learningRecord.findUnique({ where: { id } });
  }

  // ── Diagnosis ──

  @Get('user-timeline')
  async userTimeline(@Query('userId') userId?: string) {
    if (!userId) return { error: 'userId is required' };
    const events = await this.prisma.readingEvent.findMany({
      where: { userId }, orderBy: { clientTimestampMs: 'asc' }, take: 200,
      select: { eventType: true, materialId: true, clientTimestampMs: true, activeSecondsDelta: true },
    });
    return { userId, events };
  }

  @Get('user-diagnose')
  async userDiagnose(@Query('userId') userId?: string) {
    if (!userId) return { error: 'userId is required' };
    const [sessions, progressList, dailyActivities, records] = await Promise.all([
      this.prisma.learningSession.findMany({ where: { userId }, orderBy: { startedAt: 'desc' }, take: 50 }),
      this.prisma.materialReadingProgress.findMany({ where: { userId } }),
      this.prisma.dailyLearningActivity.findMany({ where: { userId }, orderBy: { activityDate: 'desc' }, take: 90 }),
      this.prisma.learningRecord.findMany({ where: { userId }, orderBy: { occurredAt: 'desc' }, take: 50 }),
    ]);
    return { userId, sessions, progressList, dailyActivities, records };
  }

  @Get('material-diagnose')
  async materialDiagnose(@Query('materialId') materialId?: string) {
    if (!materialId) return { error: 'materialId is required' };
    const [events, progress] = await Promise.all([
      this.prisma.readingEvent.findMany({ where: { materialId }, orderBy: { clientTimestampMs: 'desc' }, take: 100 }),
      this.prisma.materialReadingProgress.findMany({ where: { materialId } }),
    ]);
    return { materialId, events, progress };
  }

  @Get('anomalies')
  async anomalies() {
    const deltaOutliers = await this.prisma.readingEvent.findMany({
      where: { activeSecondsDelta: { gt: 300 } }, orderBy: { createdAt: 'desc' }, take: 50,
    });
    const futureEvents = await this.prisma.readingEvent.findMany({
      where: { clientTimestampMs: { gt: BigInt(Date.now() + 10 * 60 * 1000) } }, take: 50,
    });
    return { deltaOutliers, futureEvents };
  }

  @Get('temporary-materials')
  async listTemporaryMaterials(@Query() q: any) {
    const page = Math.max(1, Number(q.page) || 1);
    const limit = Math.min(100, Math.max(1, Number(q.limit) || 20));
    const where: any = {};
    if (q.userId) where.userId = q.userId;

    const [items, total] = await Promise.all([
      this.prisma.temporaryReadingMaterial.findMany({ where, orderBy: { createdAt: 'desc' }, skip: (page - 1) * limit, take: limit }),
      this.prisma.temporaryReadingMaterial.count({ where }),
    ]);
    return { items, total, page, limit };
  }

  // ── Operations ──

  @Post('recalculate')
  async recalculate() {
    return { message: 'Recalculation triggered', status: 'queued' };
  }

  @Get('export')
  async exportData(@Query('type') type: string, @Query('startDate') startDate?: string, @Query('endDate') endDate?: string) {
    const where: any = {};
    if (startDate) where.createdAt = { gte: new Date(startDate) };
    if (endDate) where.createdAt = { ...where.createdAt, lte: new Date(endDate) };

    const take = 5000;
    switch (type) {
      case 'events': {
        const data = await this.prisma.readingEvent.findMany({ where, take, orderBy: { createdAt: 'desc' } });
        return { type, count: data.length, data };
      }
      case 'sessions': {
        const data = await this.prisma.learningSession.findMany({ where, take, orderBy: { startedAt: 'desc' } });
        return { type, count: data.length, data };
      }
      default: return { error: 'Invalid export type. Use: events, sessions' };
    }
  }
}
