// steps.service.ts
import {
  Injectable,
  ForbiddenException,
  NotFoundException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Step, StepType } from './step.entity';
import { Lesson } from '../lessons/lesson.entity';
import { CreateStepDto } from './dto/create-step.dto';
import { UpdateStepDto } from './dto/update-step.dto';
import { promises as fs } from 'fs';
import { join } from 'path';
import { unlink } from 'fs/promises';

@Injectable()
export class StepsService {
  constructor(
    @InjectRepository(Step) private stepRepo: Repository<Step>,
    @InjectRepository(Lesson) private lessonRepo: Repository<Lesson>,
  ) { }

  async createStep(lessonId: number, dto: CreateStepDto) {
    try {
      const lesson = await this.lessonRepo.findOne({ where: { id: lessonId } });
      if (!lesson) throw new Error('Lesson not found');

      // type: 'text' or 'question' come here as JSON
      const step = this.stepRepo.create({ ...dto, lesson });
      return await this.stepRepo.save(step);
    } catch (error) {
      console.error('Error creating step:', error);
      throw error;
    }
  }

  async createVideoStep(
    lessonId: number,
    data: { title?: string; videoPath: string; type?: StepType; teleprompterText?: string },
  ) {
    const lesson = await this.lessonRepo.findOne({ where: { id: lessonId } });
    if (!lesson) throw new Error('Lesson not found');

    const step = this.stepRepo.create({
      type: data.type || 'video',
      title: data.title || 'Video',
      videoPath: data.videoPath,
      teleprompterText: data.teleprompterText,
      lesson,
    });
    return this.stepRepo.save(step);
  }

  async updateVideoStep(
    lessonId: number,
    stepId: number,
    data: { title?: string; videoPath?: string; teleprompterText?: string },
  ) {
    const step = await this.stepRepo.findOne({
      where: { id: stepId },
      relations: ['lesson'],
    });
    if (!step || step.lesson.id !== lessonId)
      throw new NotFoundException('Step not found');

    // Delete old video file if a new one is uploaded
    if (data.videoPath && step.videoPath) {
      try {
        await unlink(join(process.cwd(), step.videoPath)); // path relative to project root
      } catch (err) {
        console.warn('Old video file not found or failed to delete', err);
      }
      step.videoPath = data.videoPath;
    }

    if (data.title) step.title = data.title;
    if (data.teleprompterText) step.teleprompterText = data.teleprompterText;

    return this.stepRepo.save(step);
  }
  async getSteps(lessonId: number) {
    return this.stepRepo.find({ where: { lesson: { id: lessonId } } });
  }

  private async ensureOwnership(stepId: number, user: any) {
    const step = await this.stepRepo.findOne({
      where: { id: stepId },
      relations: ['lesson', 'lesson.course', 'lesson.course.trainer'],
    });
    if (!step) throw new NotFoundException('Step not found');
    if (user.role !== 'admin' && step.lesson.course.trainer.id !== user.id) {
      throw new ForbiddenException('You can only modify steps of your courses');
    }
    return step;
  }

  async updateStep(
    lessonId: number,
    stepId: number,
    dto: UpdateStepDto,
    user: any,
  ) {
    const step = await this.ensureOwnership(stepId, user);
    if (step.lesson.id !== lessonId)
      throw new NotFoundException('Step not in this lesson');
    Object.assign(step, dto);
    return this.stepRepo.save(step);
  }

  async deleteStep(lessonId: number, stepId: number, user: any) {
    const step = await this.ensureOwnership(stepId, user);
    if (step.lesson.id !== lessonId)
      throw new NotFoundException('Step not in this lesson');

    // If it's a video step, try to delete the physical file
    if (step.type === 'video' && step.videoPath) {
      const abs = step.videoPath.startsWith('/')
        ? join(process.cwd(), step.videoPath)
        : step.videoPath;
      try {
        await fs.unlink(abs);
      } catch {
        /* ignore if file missing */
      }
    }

    await this.stepRepo.delete(stepId);
    return { message: 'Step deleted' };
  }
  async reorderSteps(
    lessonId: number,
    orderArr: { stepId: number; order: number }[],
  ) {
    const steps = await this.stepRepo.find({
      where: { lesson: { id: lessonId } },
    });

    const updates = orderArr.map(({ stepId, order }) => {
      const step = steps.find((s) => s.id === stepId);
      if (step) {
        step.order = order;
      }
      return step;
    });

    return this.stepRepo.save(updates.filter((step): step is Step => !!step));
  }
}
