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

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

  async findAll(params: { page?: number; pageSize?: number; categoryId?: number; isFree?: boolean }) {
    const page = Number(params.page ?? 1);
    const pageSize = Number(params.pageSize ?? 20);
    const { categoryId, isFree } = params;
    const where: any = { status: 'PUBLISHED', deletedAt: null };
    if (categoryId) where.categoryId = categoryId;
    if (isFree !== undefined) where.isFree = isFree;

    const [items, total] = await Promise.all([
      this.prisma.course.findMany({
        where,
        skip: (page - 1) * pageSize,
        take: pageSize,
        orderBy: { sortOrder: 'asc' },
        include: { category: true, chapters: { include: { lessons: true }, orderBy: { sortOrder: 'asc' } } },
      }),
      this.prisma.course.count({ where }),
    ]);

    return { items, total, page, pageSize };
  }

  async findById(id: number) {
    return this.prisma.course.findUnique({
      where: { id },
      include: {
        category: true,
        chapters: {
          orderBy: { sortOrder: 'asc' },
          include: { lessons: { orderBy: { sortOrder: 'asc' } } },
        },
      },
    });
  }

  async create(data: {
    title: string; description?: string; cover?: string; categoryId?: number;
    price?: number; isFree?: boolean; sortOrder?: number;
  }) {
    return this.prisma.course.create({ data });
  }

  async update(id: number, data: any) {
    const { chapters, ...courseData } = data;
    return this.prisma.course.update({
      where: { id },
      data: courseData,
    });
  }

  async updateWithChapters(id: number, data: any) {
    const { chapters, ...courseData } = data;
    if (chapters) {
      const existingChapters = await this.prisma.chapter.findMany({ where: { courseId: id } });
      const existingIds = existingChapters.map(c => c.id);
      const incomingIds = chapters.filter((c: any) => c.id).map((c: any) => c.id);
      const toDelete = existingIds.filter(eid => !incomingIds.includes(eid));
      for (const cid of toDelete) {
        await this.prisma.lesson.deleteMany({ where: { chapterId: cid } });
        await this.prisma.chapter.delete({ where: { id: cid } });
      }
      for (const ch of chapters) {
        if (ch.id) {
          const { lessons, id: chId, courseId, ...chData } = ch;
          await this.prisma.chapter.update({ where: { id: ch.id }, data: chData });
          if (lessons) {
            const existingLessons = await this.prisma.lesson.findMany({ where: { chapterId: ch.id } });
            const existingLessonIds = existingLessons.map(l => l.id);
            const incomingLessonIds = lessons.filter((l: any) => l.id).map((l: any) => l.id);
            const lessonsToDelete = existingLessonIds.filter(eid => !incomingLessonIds.includes(eid));
            for (const lid of lessonsToDelete) {
              await this.prisma.lesson.delete({ where: { id: lid } });
            }
            for (const le of lessons) {
              if (le.id) {
                const { id: lessonId, chapterId, ...lessonData } = le;
                await this.prisma.lesson.update({ where: { id: le.id }, data: lessonData });
              } else {
                const { id: _li, ...lessonData } = le;
                await this.prisma.lesson.create({ data: { ...lessonData, chapterId: ch.id } });
              }
            }
          }
        } else {
          const { lessons, id: _newChId, ...chData } = ch;
          const newCh = await this.prisma.chapter.create({ data: { ...chData, courseId: id } });
          if (lessons) {
            for (const le of lessons) {
              const { id: _li, ...lessonData } = le;
              await this.prisma.lesson.create({ data: { ...lessonData, chapterId: newCh.id } });
            }
          }
        }
      }
    }
    return this.prisma.course.update({
      where: { id },
      data: courseData,
      include: { chapters: { include: { lessons: { orderBy: { sortOrder: 'asc' } } }, orderBy: { sortOrder: 'asc' } } },
    });
  }

  async remove(id: number) {
    return this.prisma.course.update({ where: { id }, data: { deletedAt: new Date() } });
  }

  async updateProgress(userId: number, courseId: number, lessonId: number, completed?: boolean, progress?: number) {
    const existing = await this.prisma.learnRecord.findUnique({
      where: { userId_lessonId: { userId, lessonId } },
    });

    if (existing) {
      return this.prisma.learnRecord.update({
        where: { id: existing.id },
        data: {
          completed: completed ?? existing.completed,
          progress: progress ?? existing.progress,
        },
      });
    } else {
      return this.prisma.learnRecord.create({
        data: {
          userId,
          courseId,
          lessonId,
          completed: completed ?? false,
          progress: progress ?? 0,
        },
      });
    }
  }

  async getLearningProgress(userId: number, courseId?: number) {
    const where: any = { userId };
    if (courseId) {
      where.courseId = courseId;
    }

    const records = await this.prisma.learnRecord.findMany({
      where,
      include: {
        course: { select: { id: true, title: true } },
        lesson: { select: { id: true, title: true, chapterId: true } },
      },
    });

    const courseMap: Record<number, any> = {};
    records.forEach(r => {
      if (!courseMap[r.courseId]) {
        courseMap[r.courseId] = {
          courseId: r.courseId,
          courseTitle: r.course.title,
          totalLessons: 0,
          completedLessons: 0,
          progress: 0,
          records: [],
        };
      }
      courseMap[r.courseId].records.push(r);
      courseMap[r.courseId].totalLessons++;
      if (r.completed) courseMap[r.courseId].completedLessons++;
    });

    Object.values(courseMap).forEach(c => {
      c.progress = c.totalLessons > 0 ? Math.round((c.completedLessons / c.totalLessons) * 100) : 0;
    });

    return {
      items: Object.values(courseMap),
      total: records.length,
    };
  }
}
