import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
  Query,
  Req,
  Res,
  UploadedFile,
  UseGuards,
} from "@nestjs/common";
import { Request, Response } from "express";
import { ParseObjectIdPipe } from "@nestjs/mongoose";
import { TrainingPlanService } from "./training-plan.service";
import { UserAuthGuard } from "src/common/guards/jwt-auth.guard";
import { RolesGuard } from "src/common/guards/roles.guard";
import { Roles } from "src/common/decorator/roles.decorator";
import { RoleEnum } from "src/common/enums/constant.enum";
import { CreateTrainingPlanDto } from "./dto/create-training-plan.dto";
import { UpdateTrainingPlanDto } from "./dto/update-training-plan.dto";
import { UserDecorator } from "src/common/decorator/user.decorator";
import { UploadAttachments } from "src/common/decorator/upload.decorator";
import { FileStorageService } from "src/storage/storage.service";

@Controller("training-plan")
export class TrainingPlanController {
  constructor(
    private readonly trainingPlanService: TrainingPlanService,
    private readonly fileStorageService: FileStorageService,
  ) {}

  @UseGuards(UserAuthGuard, RolesGuard)
  @Roles(RoleEnum.ADMIN , RoleEnum.USER)
  @Post("create")
  @UploadAttachments({ fieldName: "attachment" })
  async createPlan(
    @UploadedFile() file: Express.Multer.File,
    @Body() rawBody: any,
    @Req() req: Request,
    @Res() res: Response,
    @UserDecorator() user: any
  ) {
    try {
      // form-data requests carry the plan JSON in a "data" field;
      // plain JSON requests keep working unchanged
      const body: CreateTrainingPlanDto =
        typeof rawBody?.data === "string" ? JSON.parse(rawBody.data) : rawBody;

      if (file) {
        const savedFile = await this.fileStorageService.save(file, {
          subject_type: "training_plan",
          folder: "training-plans",
        });
        body.attachment = savedFile.path;
      }
      return this.trainingPlanService.createPlan(body, req, res, user);
    } catch (error) {
      return res.status(400).json({
        status: false,
        message: "Invalid JSON format. Remove comments and use double quotes.",
        error: error.message,
      });
    }
  }

  @UseGuards(UserAuthGuard)
  @Get()
  getAllPlans(
    @Req() req: Request,
    @Res() res: Response,
    @Query("page") page: number,
    @Query("limit") limit: number,
    @Query("search") search: string,
    @Query("status") status: string ,
    @UserDecorator() user: any
  ) {
    return this.trainingPlanService.getAllPlans(req, res, page, limit, search, status, user);
  }

  @UseGuards(UserAuthGuard)
  @Get("list")
  getAllPlansWithoutPagination(
    @Req() req: Request,
    @Res() res: Response,
    @Query("search") search: string,
    @Query("status") status: string,
    @UserDecorator() user: any
  ) {
    return this.trainingPlanService.getAllPlansWithoutPagination(req, res, search, status, user);
  }

  @UseGuards(UserAuthGuard)
  @Get("admin/list")
  getAllAdminPlans(
    @Req() req: Request,
    @Res() res: Response,
    @Query("page") page: number,
    @Query("limit") limit: number,
    @Query("search") search: string,
    @Query("status") status: string
  ) {
    return this.trainingPlanService.getAllAdminPlans(
      req,
      res,
      page,
      limit,
      search,
      status
    );
  }

  @UseGuards(UserAuthGuard)
  @Get(":id/details")
  getPlanFullDetailById(
    @Param("id", new ParseObjectIdPipe()) id: string,
    @Req() req: Request,
    @Res() res: Response,
    @UserDecorator() user: any
  ) {
    return this.trainingPlanService.getPlanFullDetailById(id, req, res, user);
  }

  @UseGuards(UserAuthGuard)
  @Get(":id")
  getPlanById(
    @Param("id", new ParseObjectIdPipe()) id: string,
    @Req() req: Request,
    @Res() res: Response,
    @UserDecorator() user: any
  ) {
    return this.trainingPlanService.getPlanById(id, req, res, user);
  }

  @UseGuards(UserAuthGuard, RolesGuard)
  @Roles(RoleEnum.ADMIN, RoleEnum.USER)
  @Patch(":id")
  @UploadAttachments({ fieldName: "attachment" })
  async updatePlan(
    @Param("id", new ParseObjectIdPipe()) id: string,
    @UploadedFile() file: Express.Multer.File,
    @Body() rawBody: any,
    @Req() req: Request,
    @Res() res: Response,
    @UserDecorator() user: any
  ) {
    try {
      const body: UpdateTrainingPlanDto =
        typeof rawBody?.data === "string" ? JSON.parse(rawBody.data) : rawBody;

      if (file) {
        const savedFile = await this.fileStorageService.save(file, {
          subject_type: "training_plan",
          subject_id: id,
          folder: "training-plans",
        });
        body.attachment = savedFile.path;
      }
      return this.trainingPlanService.updatePlan(id, body, req, res, user);
    } catch (error) {
      return res.status(400).json({
        status: false,
        message: "Invalid JSON format. Remove comments and use double quotes.",
        error: error.message,
      });
    }
  }

  @UseGuards(UserAuthGuard, RolesGuard)
  @Roles(RoleEnum.ADMIN, RoleEnum.USER)
  @Delete(":id")
  deletePlan(
    @Param("id", new ParseObjectIdPipe()) id: string,
    @Req() req: Request,
    @Res() res: Response,
    @UserDecorator() user: any
  ) {
    return this.trainingPlanService.deletePlan(id, req, res, user);
  }
}
