import { Router } from "express";

import { authenticate, authorize } from "../../middleware/auth.js";
import { validate } from "../../middleware/validate.js";
import { asyncHandler } from "../../utils/http.js";
import {
  bookingCreateSchema,
  bookingDetachSchema,
  bookingParamsSchema,
  bookingPatchSchema,
  bookingScopePatchSchema,
  bookingQuerySchema
} from "./bookings.schemas.js";
import {
  createBookings,
  detachBookingFromProject,
  deleteBooking,
  deleteBookingScope,
  getBookingById,
  listBookings,
  syncBookingProjectScope,
  updateBooking
} from "./bookings.service.js";

export const bookingsRouter = Router();

bookingsRouter.get(
  "/",
  authenticate,
  authorize("admin", "operator", "viewer"),
  validate({ query: bookingQuerySchema }),
  asyncHandler(async (request, response) => {
    const data = await listBookings({
      itemId: request.query.itemId as string | undefined,
      categoryId: request.query.categoryId as string | undefined,
      customerName: request.query.customerName as string | undefined,
      from: request.query.from as string | undefined,
      to: request.query.to as string | undefined
    });

    response.json({ data });
  })
);

bookingsRouter.get(
  "/:id",
  authenticate,
  authorize("admin", "operator", "viewer"),
  validate({ params: bookingParamsSchema }),
  asyncHandler(async (request, response) => {
    response.json({ data: await getBookingById(request.params.id as string) });
  })
);

bookingsRouter.post(
  "/",
  authenticate,
  authorize("admin", "operator"),
  validate({ body: bookingCreateSchema }),
  asyncHandler(async (request, response) => {
    const created = await createBookings({
      ...request.body,
      createdBy: request.authUser?.id ?? null
    });

    response.status(201).json({ data: created });
  })
);

bookingsRouter.patch(
  "/:id/detach",
  authenticate,
  authorize("admin", "operator"),
  validate({ params: bookingParamsSchema, body: bookingDetachSchema }),
  asyncHandler(async (request, response) => {
    const updated = await detachBookingFromProject(request.params.id as string, request.body.scopeBookingIds);
    response.json({ data: updated });
  })
);

bookingsRouter.patch(
  "/:id/scope",
  authenticate,
  authorize("admin", "operator"),
  validate({ params: bookingParamsSchema, body: bookingScopePatchSchema }),
  asyncHandler(async (request, response) => {
    const updated = await syncBookingProjectScope(request.params.id as string, request.body);
    response.json({ data: updated });
  })
);

bookingsRouter.patch(
  "/:id",
  authenticate,
  authorize("admin", "operator"),
  validate({ params: bookingParamsSchema, body: bookingPatchSchema }),
  asyncHandler(async (request, response) => {
    const updated = await updateBooking(request.params.id as string, request.body);
    response.json({ data: updated });
  })
);

bookingsRouter.delete(
  "/:id/scope",
  authenticate,
  authorize("admin", "operator"),
  validate({ params: bookingParamsSchema }),
  asyncHandler(async (request, response) => {
    const deleted = await deleteBookingScope(request.params.id as string);
    response.json({ data: { deleted } });
  })
);

bookingsRouter.delete(
  "/:id",
  authenticate,
  authorize("admin", "operator"),
  validate({ params: bookingParamsSchema }),
  asyncHandler(async (request, response) => {
    await deleteBooking(request.params.id as string);
    response.status(204).send();
  })
);
