import {
  Controller,
  Put,
  Post,
  Param,
  Body,
  Delete,
  UseGuards,
  Req,
  ParseIntPipe,
  Get,
  UseInterceptors,
  UploadedFiles,
  BadRequestException,
  Patch,
  Query,
} from '@nestjs/common';
import * as fs from 'fs';
import { CoursesService } from './courses.service';
import { CreateCourseDto } from './dto/create-course.dto';
import { UpdateCourseDto } from './dto/update-course.dto';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { OptionalJwtAuthGuard } from '../auth/optional-jwt-auth.guard';
import { Roles } from '../auth/roles.decorator';
import { RolesGuard } from '../auth/roles.guard';
import { FileFieldsInterceptor } from '@nestjs/platform-express';
import { diskStorage } from 'multer';
import { extname } from 'path';
import { UpdatePublishStatusDto } from './dto/update-publish-status.dto';
import { JwtService } from '@nestjs/jwt';

function fileName(_req, file, cb) {
  const unique = Date.now() + '-' + Math.round(Math.random() * 1e9);
  cb(null, unique + extname(file.originalname));
}

function fileFilter(_req, file, cb) {
  if (file.fieldname === 'courseImage') {
    if (!file.mimetype.startsWith('image/')) {
      return cb(new BadRequestException('Invalid image format'), false);
    }
  } else if (file.fieldname === 'courseVideo') {
    if (!file.mimetype.startsWith('video/')) {
      return cb(new BadRequestException('Invalid video format'), false);
    }
  }
  cb(null, true);
}

@Controller('courses')
export class CoursesController {
  constructor(
    private coursesService: CoursesService,
    private jwtService: JwtService
  ) { }

  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('trainer', 'admin')
  @Post('create')
  @UseInterceptors(
    FileFieldsInterceptor(
      [
        { name: 'courseImage', maxCount: 1 },
        { name: 'courseVideo', maxCount: 1 },
      ],
      {
        storage: diskStorage({
          destination: (req, file, cb) => {
            const dest =
              file.fieldname === 'courseImage'
                ? './uploads/courses/images'
                : './uploads/courses/videos';
            if (!fs.existsSync(dest)) {
              fs.mkdirSync(dest, { recursive: true });
            }

            cb(null, dest);
          },
          filename: fileName,
        }),
        fileFilter: fileFilter,
        limits: { fileSize: 1024 * 1024 * 500 },
      },
    ),
  )
  create(
    @Body() dto: CreateCourseDto,
    @Req() req,
    @UploadedFiles()
    files: {
      courseImage?: Express.Multer.File[];
      courseVideo?: Express.Multer.File[];
    },
  ) {
    if (files.courseImage?.[0]) {
      dto.courseImage = `/uploads/courses/images/${files.courseImage[0].filename}`;
    }
    if (files.courseVideo?.[0]) {
      dto.courseVideo = `/uploads/courses/videos/${files.courseVideo[0].filename}`;
    }
    return this.coursesService.createCourse(dto, req.user);
  }

  @UseGuards(OptionalJwtAuthGuard)
  @Get('findAll')
  findAll(@Req() req) {
    const userId = req.user?.id ?? null;
    return this.coursesService.findAll(userId);
  }

  @UseGuards(OptionalJwtAuthGuard)
  @Get(':courseId/content')
  async courseContent(
    @Req() req,
    @Param('courseId', ParseIntPipe) courseId: number,
  ) {
    const userId = req.user?.id ?? null;
    return this.coursesService.getCourseContentForUser(userId, courseId);
  }

  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('trainer', 'admin')
  @Put(':id')
  @UseInterceptors(
    FileFieldsInterceptor(
      [
        { name: 'courseImage', maxCount: 1 },
        { name: 'courseVideo', maxCount: 1 },
      ],
      {
        storage: diskStorage({
          destination: (req, file, cb) => {
            const dest =
              file.fieldname === 'courseImage'
                ? './uploads/courses/images'
                : './uploads/courses/videos';
            cb(null, dest);
          },
          filename: fileName,
        }),
        fileFilter: fileFilter,
        limits: { fileSize: 1024 * 1024 * 500 }, // 500MB
      },
    ),
  )
  update(
    @Param('id') id: string,
    @Body() dto: UpdateCourseDto,
    @Req() req,
    @UploadedFiles()
    files: {
      courseImage?: Express.Multer.File[];
      courseVideo?: Express.Multer.File[];
    },
  ) {
    if (files.courseImage?.[0]) {
      dto.courseImage = `/uploads/courses/images/${files.courseImage[0].filename}`;
    }
    if (files.courseVideo?.[0]) {
      dto.courseVideo = `/uploads/courses/videos/${files.courseVideo[0].filename}`;
    }
    return this.coursesService.updateCourse(+id, dto, req.user);
  }

  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('trainer', 'admin')
  @Delete(':id')
  remove(@Param('id') id: string, @Req() req) {
    return this.coursesService.deleteCourse(+id, req.user);
  }

  @Get('getTrainerProfile/:trainerId')
  async getTrainerProfile(@Param('trainerId', ParseIntPipe) trainerId: number) {
    return this.coursesService.getTrainerProfile(trainerId);
  }

  @UseGuards(JwtAuthGuard, RolesGuard)
  @Roles('trainer', 'admin')
  @Patch(':id/publish')
  updatePublishStatus(
    @Param('id', ParseIntPipe) id: number,
    @Body() dto: UpdatePublishStatusDto,
    @Req() req,
  ) {
    return this.coursesService.updatePublishStatus(id, dto.isPublished, req.user);
  }

  @Get('approve')
  async approvePublish(@Query('token') token: string) {
    if (!token) throw new BadRequestException('Token is required');
    try {
      const payload = this.jwtService.verify(token);
      if (payload.action !== 'approve') throw new BadRequestException('Invalid action');
      return this.coursesService.approvePublish(payload.courseId);
    } catch (e) {
      throw new BadRequestException('Invalid or expired token');
    }
  }

  @Get('reject')
  async rejectPublish(@Query('token') token: string) {
    if (!token) throw new BadRequestException('Token is required');
    try {
      const payload = this.jwtService.verify(token);
      if (payload.action !== 'reject') throw new BadRequestException('Invalid action');
      return this.coursesService.rejectPublish(payload.courseId);
    } catch (e) {
      throw new BadRequestException('Invalid or expired token');
    }
  }
}
