import {
  Injectable,
  ForbiddenException,
  NotFoundException,
  BadRequestException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Enrollment } from './enrollment.entity';
import { CourseProgress } from '../progress/course-progress.entity';
import { Course } from '../course/course.entity';
import { Lesson } from '../lessons/lesson.entity';
import { Step } from '../steps/step.entity';
import { ConfigService } from '@nestjs/config';
import { MailService } from '../mail/mail.service';

@Injectable()
export class EnrollmentsService {
  constructor(
    @InjectRepository(Enrollment)
    private readonly enrollRepo: Repository<Enrollment>,
    @InjectRepository(Course) private readonly courseRepo: Repository<Course>,
    @InjectRepository(Lesson) private readonly lessonRepo: Repository<Lesson>,
    @InjectRepository(Step) private readonly stepRepo: Repository<Step>,
    @InjectRepository(CourseProgress)
    private readonly progressRepo: Repository<CourseProgress>,
    private readonly config: ConfigService,
    private readonly mailService: MailService,
  ) { }

  async myCourses(id: number) {
    const enrolls = await this.enrollRepo.find({
      where: { user: { id: id }, status: 'active' },
    });
    const progress = await this.progressRepo.find({
      where: { user: { id: id } },
    });
    const map = new Map(progress.map((p) => [p.course.id, p]));
    return enrolls.map((e) => ({
      course: e.course,
      subscribedAt: e.subscribedAt,
      status: e.status,
      user: e.user,
      progress: map.get(e.course.id) || null,
    }));
  }

  // async updateProgress(id: number, courseId: number, lastLessonId?: number, lastStepId?: number, completed?: boolean) {
  //   // ensure user owns an active enrollment
  //   const enroll = await this.enrollRepo.findOne({ where: { user: { id: id }, course: { id: courseId }, status: 'active' } });
  //   if (!enroll) throw new ForbiddenException('Not enrolled');

  //   let p = await this.progressRepo.findOne({ where: { user: { id: id }, course: { id: courseId } } });
  //   if (!p) {
  //     p = this.progressRepo.create({ user: { id: id } as any, course: { id: courseId } as any });
  //   }
  //   if (lastLessonId) p.lastLesson = { id: lastLessonId } as any;
  //   if (lastStepId) p.lastStep = { id: lastStepId } as any;
  //   if (typeof completed === 'boolean') p.completed = completed;

  //   // optional: compute % based on total steps
  //   return this.progressRepo.save(p);
  // }

  async updateProgress(
    userId: number,
    courseId: number,
    lastLessonId?: number,
    lastStepId?: number,
  ) {
    const enroll = await this.enrollRepo.findOne({
      where: {
        user: { id: userId },
        course: { id: courseId },
        status: 'active',
      },
    });
    if (!enroll) throw new ForbiddenException('Not enrolled');

    const course = await this.courseRepo.findOne({
      where: { id: courseId },
      relations: ['lessons', 'lessons.steps'],
    });
    if (!course) throw new NotFoundException('Course not found');

    const lessons = course.lessons.filter((l) => l.steps.length > 0);
    if (lessons.length === 0)
      throw new BadRequestException('Course has no steps');

    // حساب جميع الخطوات في كورس كامل
    const allSteps: { lessonId: number; stepId: number }[] = [];
    for (const lesson of lessons) {
      for (const step of lesson.steps) {
        allSteps.push({ lessonId: lesson.id, stepId: step.id });
      }
    }

    // تحديد عدد الخطوات المكتملة بناءً على آخر خطوة
    let completedSteps = 0;
    for (const s of allSteps) {
      completedSteps++;
      if (s.lessonId === lastLessonId && s.stepId === lastStepId) break;
    }

    const percent = Math.min(
      Math.round((completedSteps / allSteps.length) * 100),
      100,
    );

    const lastLesson = lessons[lessons.length - 1];
    const lastStep = lastLesson.steps[lastLesson.steps.length - 1];
    const completed =
      lastLesson.id === lastLessonId && lastStep.id === lastStepId;

    let progress = await this.progressRepo.findOne({
      where: { user: { id: userId }, course: { id: courseId } },
    });

    if (!progress) {
      progress = this.progressRepo.create({
        user: { id: userId } as any,
        course: { id: courseId } as any,
      });
    }

    const wasCompleted = progress?.completed || false;
    progress.lastLesson = lastLessonId ? ({ id: lastLessonId } as any) : null;
    progress.lastStep = lastStepId ? ({ id: lastStepId } as any) : null;
    progress.percent = percent;
    progress.completed = completed;

    const saved = await this.progressRepo.save(progress);

    // Send completion email if newly completed
    if (completed && !wasCompleted) {
      const user = await this.enrollRepo.findOne({
        where: { user: { id: userId }, course: { id: courseId } },
        relations: ['user'],
      });
      if (user?.user) {
        this.mailService.sendCourseCompletion(user.user.email, '', course.title);
      }
    }

    return saved;
  }

  /**
   * Return full course (lessons + steps) for an active learner.
   * Guards:
   *  - Must have enrollment.status === 'active'
   */
  async getCourseContentForUser(id: number, courseId: number) {
    // 1) Check active enrollment
    const enrollment = await this.enrollRepo.findOne({
      where: { user: { id: id }, course: { id: courseId }, status: 'active' },
      relations: { course: false },
    });
    if (!enrollment) {
      throw new ForbiddenException('You are not enrolled in this course.');
    }

    // 2) Load course with nested lessons+steps
    const course = await this.courseRepo.findOne({
      where: { id: courseId },
      relations: {
        lessons: { steps: true },
        trainer: true,
      },
      order: {
        lessons: {
          id: 'ASC',
          steps: { order: 'ASC' }, // sort steps by their "order" column
        },
      } as any,
    });
    if (!course) throw new NotFoundException('Course not found');

    // Optional: sort steps inside each lesson (by id or "order" if you have it)
    for (const lesson of course.lessons || []) {
      lesson.steps?.sort((a, b) => a.order - b.order);
    }

    // 3) Get latest progress (optional)
    const progress = await this.progressRepo.findOne({
      where: { user: { id: id }, course: { id: courseId } },
      relations: { lastLesson: true, lastStep: true },
    });
    const lessonsWithSteps = (course.lessons || [])
      .filter((l) => Array.isArray(l.steps) && l.steps.length > 0)
      .map((l) => {
        l.steps.sort((a, b) => a.id - b.id); // or by l.steps order field if you add one
        return l;
      });
    // 4) Build public video URL if you save "videoPath"
    const baseUrl = this.config.get<string>('APP_BASE_URL') ?? '';
    const mapStep = (s: Step) => {
      const out: any = {
        id: s.id,
        type: s.type,
        title: s.title,
        content: s.content,
        questionData: s.questionData,
      };
      if ((s as any).videoPath) {
        const vp = (s as any).videoPath as string;
        out.videoUrl = vp.startsWith('http')
          ? vp
          : `${baseUrl}/uploads/${vp.replace(/^\/?uploads\//, '')}`;
      }
      return out;
    };

    // 5) Return only necessary fields (avoid sending hashed passwords, etc.)
    return {
      enrollment: {
        status: enrollment.status,
        subscribedAt: enrollment.subscribedAt,
      },
      progress: progress
        ? {
          lastLesson: progress.lastLesson
            ? { id: progress.lastLesson.id, title: progress.lastLesson.title }
            : null,
          lastStep: progress.lastStep
            ? { id: progress.lastStep.id, title: progress.lastStep.title }
            : null,
          percent: progress.percent,
          completed: progress.completed,
          updatedAt: progress.updatedAt,
        }
        : null,
      course: {
        id: course.id,
        title: course.title,
        description: course.description,
        duration: course.duration,
        price: course.price,
        discountPrice: course.discountPrice,
        level: course.level,
        isPublished: course.isPublished,
        trainer: course.trainer,
        lessons: (course.lessons || []).map((l) => ({
          id: l.id,
          title: l.title,
          description: l.description,
          steps: (l.steps || []).map(mapStep),
        })),
      },
    };
  }
}
