import { Injectable, ForbiddenException, NotFoundException, BadRequestException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Course } from './course.entity';
import { CreateCourseDto } from './dto/create-course.dto';
import { UpdateCourseDto } from './dto/update-course.dto';
import { User } from '../users/user.entity';
import { Enrollment } from '../enrollments/enrollment.entity';
import { Step } from '../steps/step.entity';
import { ConfigService } from '@nestjs/config';
import { CourseProgress } from '../progress/course-progress.entity';
import { MailService } from '../mail/mail.service';

@Injectable()
export class CoursesService {
  constructor(
    @InjectRepository(Course)
    private coursesRepo: Repository<Course>,

    @InjectRepository(Enrollment)
    private enrollmentRepo: Repository<Enrollment>,


    @InjectRepository(CourseProgress)
    private progressRepo: Repository<CourseProgress>,

    @InjectRepository(User) private userRepo: Repository<User>,

    private readonly config: ConfigService,
    private readonly mailService: MailService,
  ) { }

  async createCourse(dto: CreateCourseDto, trainer) {
    if (trainer.role !== 'trainer') {
      throw new ForbiddenException('Only trainers can create courses');
    }

    const course = this.coursesRepo.create({
      ...dto,
      trainer: { id: trainer.id },
    });
    return this.coursesRepo.save(course);
  }

  async findAll(userId: number | null) {
    const courses = await this.coursesRepo.find({ where: { isPublished: true } });

    if (!userId) {
      return courses;
    }

    const out: any[] = [];
    for (const course of courses) {
      const item: any = {
        ...course,
        courseImage: course.courseImage ? process.env.APP_BASE_URL + course.courseImage : null,
        courseVideo: course.courseVideo ? process.env.APP_BASE_URL + course.courseVideo : null,
        action: 'pay'
      };

      const enrollment = await this.enrollmentRepo.findOne({
        where: { user: { id: userId }, course: { id: course.id } },
        relations: { user: true, course: true },
      });

      if (enrollment?.status === 'active') {
        const progress = await this.progressRepo.findOne({
          where: { user: { id: userId }, course: { id: course.id } },
          relations: { lastLesson: true, lastStep: true },
        });

        item.action = progress ? 'continueWatching' : 'startCourse';
        item.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;
      } else {
        item.action = 'pay';
      }

      out.push(item);
    }

    return out;
  }

  async findById(id: number) {
    return this.coursesRepo.findOne({ where: { id, isPublished: true } });
  }

  async updateCourse(id: number, dto: UpdateCourseDto, user: User) {
    const course = await this.coursesRepo.findOne({ where: { id }, relations: ['trainer'] });
    if (!course) throw new NotFoundException('Course not found');
    if (user.role !== 'admin' && course.trainer.id !== user.id) {
      throw new ForbiddenException('You can only update your own courses');
    }
    Object.assign(course, dto);
    return this.coursesRepo.save(course);
  }

  async updatePublishStatus(id: number, isPublished: boolean, user: User) {
    const course = await this.coursesRepo.findOne({ where: { id }, relations: ['trainer'] });
    if (!course) throw new NotFoundException('Course not found');

    // Admin can toggle immediately
    if (user.role === 'admin') {
      course.isPublished = isPublished;
      course.publishStatus = isPublished ? 'published' : 'draft';
      return this.coursesRepo.save(course);
    }

    // Trainer requests approval
    if (course.trainer.id !== user.id) {
      throw new ForbiddenException('You can only update your own courses');
    }

    course.publishStatus = 'pending';
    // isPublished remains unchanged until admin approves
    await this.coursesRepo.save(course);

    const trainerName = course.trainer['name'] || course.trainer.email.split('@')[0];
    await this.mailService.sendCourseApprovalRequest(
      trainerName,
      course.title,
      course.id,
      isPublished // This is the requested target state
    );

    return {
      message: 'Request sent to administrator for approval',
      status: 'pending'
    };
  }

  async approvePublish(id: number) {
    const course = await this.coursesRepo.findOne({ where: { id } });
    if (!course) throw new NotFoundException('Course not found');

    if (course.publishStatus !== 'pending') {
      return `
        <div style="font-family: sans-serif; text-align: center; padding: 50px;">
          <h1 style="color: #6b7280;">Request Already Processed</h1>
          <p>This approval link for "${course.title}" is no longer valid or has already been handled.</p>
        </div>
      `;
    }

    // Safe Toggle: Flip the current state
    course.isPublished = !course.isPublished;
    course.publishStatus = course.isPublished ? 'published' : 'draft';

    await this.coursesRepo.save(course);

    console.log(`[APPROVAL] Course ${id} processed. New state: isPublished=${course.isPublished}`);

    return `
      <div style="font-family: sans-serif; text-align: center; padding: 50px;">
        <div style="font-size: 50px; margin-bottom: 20px;">✅</div>
        <h1 style="color: #10b981;">Successfully Approved!</h1>
        <p>The course "${course.title}" is now ${course.isPublished ? 'Live' : 'Hidden'}.</p>
      </div>
    `;
  }

  async rejectPublish(id: number) {
    const course = await this.coursesRepo.findOne({ where: { id } });
    if (!course) throw new NotFoundException('Course not found');

    if (course.publishStatus !== 'pending') {
      return `
        <div style="font-family: sans-serif; text-align: center; padding: 50px;">
          <h1 style="color: #6b7280;">Request Already Processed</h1>
          <p>This rejection link is no longer valid.</p>
        </div>
      `;
    }

    // Revert status from pending back to its current state
    course.publishStatus = course.isPublished ? 'published' : 'draft';

    await this.coursesRepo.save(course);
    return `
      <div style="font-family: sans-serif; text-align: center; padding: 50px;">
        <div style="font-size: 50px; margin-bottom: 20px;">❌</div>
        <h1 style="color: #ef4444;">Request Rejected</h1>
        <p>The status of "${course.title}" remains unchanged.</p>
      </div>
    `;
  }

  async deleteCourse(id: number, user: User) {
    const course = await this.coursesRepo.findOne({ where: { id }, relations: ['trainer'] });
    if (!course) throw new NotFoundException('Course not found');
    if (user.role !== 'admin' && course.trainer.id !== user.id) {
      throw new ForbiddenException('You can only delete your own courses');
    }

    // Check if there are any enrollments
    const enrollments = await this.enrollmentRepo.count({ where: { course: { id } } });
    if (enrollments > 0) {
      throw new BadRequestException('Cannot delete course because there are existing enrollments');
    }

    // No enrollments → safe to delete
    await this.coursesRepo.delete(id);
    return { message: 'Course deleted successfully' };
  }


  // async getCourseContentForUser(courseId: number) {

  //   // 2) Load course with nested lessons+steps
  //   const course = await this.coursesRepo.findOne({
  //     where: { id: courseId },
  //     relations: {
  //       lessons: { steps: true },
  //       trainer: true,
  //     },
  //     order: {
  //       lessons: { id: 'ASC' },   // adjust to 'order' column if you have it
  //     } 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.id - b.id);
  //   }


  //   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;
  //   };

  //   return {
  //     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),
  //       })),
  //     },
  //   };
  // }
  async getCourseContentForUser(userId: number | null, courseId: number) {
    // 1) Load course
    const course = await this.coursesRepo.findOne({
      where: { id: courseId },
      relations: { lessons: { steps: true }, trainer: true },
      order: {
        lessons: {
          id: 'ASC',
          steps: { order: 'ASC' }, // ✅ sort by order
        },
      } as any,
    });
    if (!course) throw new NotFoundException('Course not found');

    // 2) Clean up steps order
    const lessonsWithSteps = (course.lessons || [])
      .filter(l => Array.isArray(l.steps) && l.steps.length > 0)
      .map(l => {
        l.steps.sort((a, b) => a.order - b.order);
        return l;
      });

    // 3) Map steps to include video URLs
    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,
        order: s.order,
        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;
    };

    // 4) Default response
    const result: any = {
      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,
        ratingAvg: course.ratingAvg,
        ratingCount: course.ratingCount,
        courseImage: course.courseImage ? process.env.APP_BASE_URL + course.courseImage : null,
        courseVideo: course.courseVideo ? process.env.APP_BASE_URL + course.courseVideo : null,
        trainer: { id: course.trainer.id, email: course.trainer.email },
        lessons: lessonsWithSteps.map(l => ({
          id: l.id,
          title: l.title,
          description: l.description,
          steps: (l.steps || []).map(mapStep),
        })),
      },
      action: 'pay', // default
    };

    // 5) If logged in, check enrollment
    if (userId) {
      const enrollment = await this.enrollmentRepo.findOne({
        where: { user: { id: userId }, course: { id: courseId } },
        relations: { user: true, course: true },
      });

      if (enrollment?.status === 'active') {
        // check progress
        const progress = await this.progressRepo.findOne({
          where: { user: { id: userId }, course: { id: courseId } },
          relations: { lastLesson: true, lastStep: true },
        });

        result.action = progress
          ? 'continueWatching'
          : 'startCourse';
        result.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;
      } else {
        result.action = 'pay'; // enrolled but pending or not enrolled
      }
    }

    return result;
  }

  async getTrainerProfile(trainerId: number) {
    // 1) Get trainer basic info
    const trainer = await this.userRepo.findOne({
      where: { id: trainerId, role: 'trainer' },
    });
    if (!trainer) throw new NotFoundException('Trainer not found');

    // 2) Get all published courses by this trainer
    const courses = await this.coursesRepo.find({
      where: { trainer: { id: trainerId }, isPublished: true },
      relations: { lessons: true },
      order: { id: 'DESC' },
    });

    // 3) Clean response
    return {
      trainer: {
        id: trainer.id,
        name: trainer['name'] ?? trainer.email.split('@')[0],
        email: trainer.email,
        phone: trainer.phone,
        gender: trainer.gender,
      },
      courses: courses.map(c => ({
        id: c.id,
        title: c.title,
        description: c.description,
        level: c.level,
        duration: c.duration,
        price: c.price,
        discountPrice: c.discountPrice,
        ratingAvg: c.ratingAvg,
        ratingCount: c.ratingCount,
        isPublished: c.isPublished,
        courseImage: c.courseImage ? process.env.APP_BASE_URL + c.courseImage : null,
        courseVideo: c.courseVideo ? process.env.APP_BASE_URL + c.courseVideo : null,
        lessonsCount: c.lessons?.length ?? 0,
      })),
    };
  }

}
