import { parseDateOnly } from "@batch-cooking/date-tools";
import { HttpError } from "@batch-cooking/error-tools";
import { wrapAsyncHandler } from "@batch-cooking/express-tools";
import { addPlanningItemSchema, ErrorCode, getPlanningByDateSchema } from "@batch-cooking/shared";
import { Router } from "express";
import { type AuthLocals, requireAuth } from "../../middlewares/require-auth.js";
import { addPlanningItem, getPlanningForDate, removePlanningItem } from "./planning.service.js";

/** Router mounted at `/planning` in app.ts. */
export const planningRouter = Router();

/**
 * Returns the authenticated user's household's planning covering `?date=`
 * (`YYYY-MM-DD`), or `null` if none exists yet — a valid, common response,
 * not an error (see {@link getPlanningForDate}). Used both for "today"
 * (the planning page's initial load) and for any other week the planning
 * page's week navigator/calendar picks.
 */
planningRouter.get(
  "/",
  requireAuth,
  wrapAsyncHandler<unknown, AuthLocals>(async (req, res) => {
    const input = getPlanningByDateSchema.parse(req.query);
    const date = parseDateOnly(input.date);
    if (date === null) {
      throw new HttpError(
        400,
        ErrorCode.VALIDATION_ERROR,
        `Not a real calendar date: ${input.date}`,
      );
    }

    const planning = await getPlanningForDate(res.locals.userProfile.houseId, date);
    res.status(200).json(planning);
  }),
);

/** Parses and validates the `:id` route param shared by every `/items/:id` route below. */
function parsePlanningItemId(rawId: string | undefined): number {
  const id = Number(rawId);
  if (!Number.isInteger(id)) {
    throw new HttpError(400, ErrorCode.VALIDATION_ERROR, "id must be an integer");
  }
  return id;
}

/**
 * Adds a recipe to one (day, meal) slot of the authenticated user's
 * household's planning, creating that week's `Planning` row on the fly if
 * needed (see {@link addPlanningItem}).
 */
planningRouter.post(
  "/items",
  requireAuth,
  wrapAsyncHandler<unknown, AuthLocals>(async (req, res) => {
    const input = addPlanningItemSchema.parse(req.body);
    const date = parseDateOnly(input.date);
    if (date === null) {
      throw new HttpError(
        400,
        ErrorCode.VALIDATION_ERROR,
        `Not a real calendar date: ${input.date}`,
      );
    }

    const { id: viewerId, houseId } = res.locals.userProfile;
    const item = await addPlanningItem(houseId, viewerId, houseId, date, input);
    res.status(201).json(item);
  }),
);

/** Removes one recipe from a planning slot. */
planningRouter.delete(
  "/items/:id",
  requireAuth,
  wrapAsyncHandler<unknown, AuthLocals>(async (req, res) => {
    const id = parsePlanningItemId(req.params.id);
    await removePlanningItem(id, res.locals.userProfile.houseId);
    res.status(204).end();
  }),
);
