import { DrizzleService } from '@lib/drizzle/src/drizzle.service';
import { Injectable } from '@nestjs/common';
import {
  CreateEnrollmentDto,
  UpsertVideoProgressDto,
} from './courses-progress.dto';
import {
  tnCourses,
  tnCoursesEnrollments,
  tnCoursesSections,
  tnCoursesVideos,
  tnCoursesVideosProgress,
} from 'drizzle/schema';
import { and, eq, inArray } from 'drizzle-orm';
import dayjs from 'dayjs';

@Injectable()
export class CoursesProgressRepository {
  constructor(private drizzle: DrizzleService) {}

  async createEnrollment(dto: CreateEnrollmentDto) {
    return this.drizzle.insert(tnCoursesEnrollments).values(dto);
  }

  async getCoursesIdByVideoId(crvId: number) {
    const [data] = await this.drizzle
      .select({
        crsId: tnCourses.crsId,
      })
      .from(tnCoursesVideos)
      .innerJoin(
        tnCoursesVideos,
        eq(tnCoursesSections.cssId, tnCoursesVideos.cssId),
      )
      .innerJoin(tnCourses, eq(tnCourses.crsId, tnCoursesSections.crsId))
      .where(eq(tnCoursesVideos.crvId, crvId));

    return data.crsId;
  }

  async upsertVideoProgress(dto: UpsertVideoProgressDto) {
    return this.drizzle
      .insert(tnCoursesVideosProgress)
      .values({
        ...dto,
        crvpCompletedAt:
          dto.crvpIsCompleted === 1
            ? dayjs().format('YYYY-MM-DD HH:mm:ss')
            : null,
        memId: dto.memId,
      })
      .onDuplicateKeyUpdate({
        set: {
          crvId: dto.crvId,
          memId: dto.memId,
          crvpLastWatchedSeconds: dto.crvpLastWatchedSeconds,
          crvpIsCompleted: dto.crvpIsCompleted,
          crvpCompletedAt:
            dto.crvpIsCompleted === 1
              ? dayjs().format('YYYY-MM-DD HH:mm:ss')
              : null,
        },
      });
  }

  async calculateUserCoursesProgress(memId: number, crsId: number) {
    //* 해당 강의에 속하는 모든 영상 가져오기
    const videos = await this.drizzle
      .select({
        crvId: tnCoursesVideos.crvId,
      })
      .from(tnCourses)
      .innerJoin(
        tnCoursesSections,
        eq(tnCoursesSections.crsId, tnCourses.crsId),
      )
      .innerJoin(
        tnCoursesVideos,
        eq(tnCoursesVideos.cssId, tnCoursesSections.cssId),
      )
      .where(eq(tnCourses.crsId, crsId));

    const videoIds = videos.map((v) => v.crvId);
    const totalVideoCount = videoIds.length;

    //* 유저가 완료한 강의 영상 수 조회
    const completedProgress = await this.drizzle
      .select()
      .from(tnCoursesVideosProgress)
      .where(
        and(
          eq(tnCoursesVideosProgress.memId, memId),
          inArray(tnCoursesVideosProgress.crvId, videoIds),
          eq(tnCoursesVideosProgress.crvpIsCompleted, 1),
        ),
      );

    const completedCount = completedProgress.length;

    //* 완료 비율 계산(영상수 기준으로 계산)
    const progressRate =
      totalVideoCount === 0 ? 0 : (completedCount / totalVideoCount) * 100;
    const isCompleted =
      totalVideoCount > 0 && completedCount === totalVideoCount;

    return await this.drizzle.update(tnCoursesEnrollments).set({
      cemProgressRate: progressRate,
      cemIsCompleted: isCompleted ? 1 : 0,
      cemCompletedAt: isCompleted
        ? dayjs().format('YYYY-MM-DD HH:mm:ss')
        : null,
    });
  }
}
