import { zValidator } from "@hono/zod-validator";
import { db, eq, and, isNotNull } from "@haushaltsApp/db";
import { shoppingItems } from "@haushaltsApp/db/schema";
import { Hono } from "hono";
import type { ShoppingServerEvent } from "@haushaltsApp/shared/schemas/shopping.schema";
import { addShoppingItemSchema } from "@haushaltsApp/shared/schemas/shopping.schema";
import { authMiddleware, requireAuth, type AuthVariables } from "../middleware/auth.middleware";
import { tenantMiddleware, requireHousehold, type TenantVariables } from "../middleware/tenant.middleware";
import { broadcast } from "../ws/shopping-ws";
import {
  getShoppingItems,
  addShoppingItem,
  checkShoppingItem,
  uncheckShoppingItem,
  deleteShoppingItem,
} from "../services/shopping.service";

type Variables = AuthVariables & TenantVariables;

export const shoppingRoutes = new Hono<{ Variables: Variables }>();
shoppingRoutes.use("/*", authMiddleware, requireAuth, tenantMiddleware, requireHousehold);

// GET /api/shopping — list all items for household
shoppingRoutes.get("/", async (c) => {
  const householdId = c.get("householdId") as string;
  const items = await getShoppingItems(householdId);
  return c.json({ items });
});

// POST /api/shopping — add an item
shoppingRoutes.post("/", zValidator("json", addShoppingItemSchema), async (c) => {
  const householdId = c.get("householdId") as string;
  const user = c.get("user") as { id: string };
  const { label, quantity } = c.req.valid("json");
  const item = await addShoppingItem(householdId, user.id, label, quantity);
  broadcast(householdId, { type: "item:added", item } satisfies ShoppingServerEvent);
  return c.json({ item }, 201);
});

// PATCH /api/shopping/:id/check
shoppingRoutes.patch("/:id/check", async (c) => {
  const householdId = c.get("householdId") as string;
  const user = c.get("user") as { id: string };
  const id = c.req.param("id");
  const item = await checkShoppingItem(id, householdId, user.id);
  if (!item) return c.json({ error: "Not found" }, 404);
  broadcast(householdId, {
    type: "item:checked",
    itemId: item.id,
    checkedBy: item.checkedBy!,
    checkedAt: item.checkedAt!,
  } satisfies ShoppingServerEvent);
  return c.json({ item });
});

// PATCH /api/shopping/:id/uncheck
shoppingRoutes.patch("/:id/uncheck", async (c) => {
  const householdId = c.get("householdId") as string;
  const id = c.req.param("id");
  const item = await uncheckShoppingItem(id, householdId);
  if (!item) return c.json({ error: "Not found" }, 404);
  broadcast(householdId, { type: "item:unchecked", itemId: id } satisfies ShoppingServerEvent);
  return c.json({ item });
});

// DELETE /api/shopping/checked — clear all checked items (must be before /:id)
shoppingRoutes.delete("/checked", async (c) => {
  const householdId = c.get("householdId") as string;
  await db
    .delete(shoppingItems)
    .where(and(eq(shoppingItems.householdId, householdId), isNotNull(shoppingItems.checkedBy)));
  broadcast(householdId, { type: "item:cleared" } satisfies ShoppingServerEvent);
  return c.json({ ok: true });
});

// DELETE /api/shopping/:id
shoppingRoutes.delete("/:id", async (c) => {
  const householdId = c.get("householdId") as string;
  const id = c.req.param("id");
  await deleteShoppingItem(id, householdId);
  broadcast(householdId, { type: "item:deleted", itemId: id } satisfies ShoppingServerEvent);
  return c.json({ ok: true });
});
