import { Body, Controller, Get, Param, Post, Req } from "@nestjs/common";
import { z } from "zod";
import {
  SchedulingService,
  type CreateCourseInput,
  type CreateScheduleInput,
} from "./scheduling.service.js";
import {
  Permissions,
  RequirePermission,
} from "../middleware/permission.guard.js";
import type { AuthenticatedRequest } from "../middleware/auth.middleware.js";
import {
  UnauthorizedError,
  ValidationError,
} from "../shared/errors/application-error.js";

const createCourseSchema = z.object({
  classId: z.string().min(1),
  subjectId: z.string().min(1),
  teacherId: z.string().min(1),
  schoolId: z.string().min(1),
  name: z.string().min(1).max(200),
  startDate: z.string().min(1),
  endDate: z.string().min(1),
});

const createScheduleSchema = z.object({
  courseId: z.string().min(1),
  lessonId: z.string().optional(),
  teacherId: z.string().min(1),
  classId: z.string().min(1),
  roomId: z.string().optional(),
  startTime: z.string().min(1),
  endTime: z.string().min(1),
  schoolId: z.string().min(1),
});

@Controller("v1")
export class SchedulingController {
  constructor(private readonly schedulingService: SchedulingService) {}

  // ----- Course endpoints -----

  @Post("courses")
  @RequirePermission(Permissions.COURSE_CREATE)
  async createCourse(
    @Body() body: unknown,
    @Req() req: AuthenticatedRequest,
  ): Promise<{ success: true; data: { id: string } }> {
    const userId = req.userId;
    if (!userId) {
      throw new UnauthorizedError("Missing x-user-id header");
    }
    const parsed = createCourseSchema.safeParse(body);
    if (!parsed.success) {
      throw new ValidationError("Invalid course input", parsed.error.flatten());
    }
    const input: CreateCourseInput = parsed.data;
    const result = await this.schedulingService.createCourse(input);
    return { success: true, data: result };
  }

  @Get("courses/:id")
  @RequirePermission(Permissions.COURSE_READ)
  async getCourse(@Param("id") id: string): Promise<{
    success: true;
    data: Awaited<ReturnType<SchedulingService["getCourse"]>>;
  }> {
    const data = await this.schedulingService.getCourse(id);
    return { success: true, data };
  }

  @Get("courses/class/:classId")
  @RequirePermission(Permissions.COURSE_READ)
  async listCoursesByClass(@Param("classId") classId: string): Promise<{
    success: true;
    data: Awaited<ReturnType<SchedulingService["listCoursesByClass"]>>;
  }> {
    const data = await this.schedulingService.listCoursesByClass(classId);
    return { success: true, data };
  }

  @Get("courses/teacher/:teacherId")
  @RequirePermission(Permissions.COURSE_READ)
  async listCoursesByTeacher(@Param("teacherId") teacherId: string): Promise<{
    success: true;
    data: Awaited<ReturnType<SchedulingService["listCoursesByTeacher"]>>;
  }> {
    const data = await this.schedulingService.listCoursesByTeacher(teacherId);
    return { success: true, data };
  }

  // ----- Schedule endpoints -----

  @Post("schedules")
  @RequirePermission(Permissions.SCHEDULE_CREATE)
  async createSchedule(
    @Body() body: unknown,
    @Req() req: AuthenticatedRequest,
  ): Promise<{ success: true; data: { id: string } }> {
    const userId = req.userId;
    if (!userId) {
      throw new UnauthorizedError("Missing x-user-id header");
    }
    const parsed = createScheduleSchema.safeParse(body);
    if (!parsed.success) {
      throw new ValidationError(
        "Invalid schedule input",
        parsed.error.flatten(),
      );
    }
    const input: CreateScheduleInput = parsed.data;
    const result = await this.schedulingService.createSchedule(input);
    return { success: true, data: result };
  }

  @Get("schedules/:id")
  @RequirePermission(Permissions.SCHEDULE_READ)
  async getSchedule(@Param("id") id: string): Promise<{
    success: true;
    data: Awaited<ReturnType<SchedulingService["getSchedule"]>>;
  }> {
    const data = await this.schedulingService.getSchedule(id);
    return { success: true, data };
  }

  @Get("schedules/course/:courseId")
  @RequirePermission(Permissions.SCHEDULE_READ)
  async listSchedulesByCourse(@Param("courseId") courseId: string): Promise<{
    success: true;
    data: Awaited<ReturnType<SchedulingService["listSchedulesByCourse"]>>;
  }> {
    const data = await this.schedulingService.listSchedulesByCourse(courseId);
    return { success: true, data };
  }

  @Get("schedules/teacher/:teacherId")
  @RequirePermission(Permissions.SCHEDULE_READ)
  async listSchedulesByTeacher(@Param("teacherId") teacherId: string): Promise<{
    success: true;
    data: Awaited<ReturnType<SchedulingService["listSchedulesByTeacher"]>>;
  }> {
    const data = await this.schedulingService.listSchedulesByTeacher(teacherId);
    return { success: true, data };
  }

  @Get("schedules/class/:classId")
  @RequirePermission(Permissions.SCHEDULE_READ)
  async listSchedulesByClass(@Param("classId") classId: string): Promise<{
    success: true;
    data: Awaited<ReturnType<SchedulingService["listSchedulesByClass"]>>;
  }> {
    const data = await this.schedulingService.listSchedulesByClass(classId);
    return { success: true, data };
  }
}
