Refactor this component - it's part of next.js app with trpc
/**
 * @file Defines the tRPC router for canteen-related endpoints.
 *
 * This router handles operations for creating, updating, and retrieving canteens
 * associated with a user's business. It follows the established pattern for routers,
 * using service helpers for business logic and Zod schemas for validation.
 */

import { TRPCError } from "@trpc/server";
import { z } from "zod";
import type { TRPCContext } from "../../trpc";
import { createTRPCRouter, permissionProcedure } from "../../trpc";
import { assertAuthenticated, generateCanteenSlug } from "./canteen.service";
import { createOwnCanteenSchema, updateOwnCanteenSchema } from "./canteen.zod";

// Helper to ensure a canteen slug is unique within a business
async function ensureUniqueCanteenName(
	ctx: TRPCContext,
	{
		name,
		city,
		businessId,
		excludeCanteenId,
	}: {
		name: string;
		city: string;
		businessId: string;
		excludeCanteenId?: string;
	},
) {
	const slug = generateCanteenSlug(name, city);
	const existing = await ctx.db.canteen.findFirst({
		where: {
			slug,
			businessId,
			id: excludeCanteenId ? { not: excludeCanteenId } : undefined,
		},
	});
	if (existing) {
		throw new TRPCError({
			code: "CONFLICT",
			message:
				"A canteen with the same name and city (slug) already exists in your business.",
		});
	}
}

export const canteenRouter = createTRPCRouter({
	listOwn: permissionProcedure("canViewOwnCanteens").query(async ({ ctx }) => {
		const user = assertAuthenticated(ctx);

		// Business owners can see all their canteens, while canteen admins see only their assigned ones.

		return ctx.db.canteen.findMany({
			where: { id: { in: user.canteenAccess ?? [] } },
			include: {
				address: true,
			},
		});
	}),

	createOwn: permissionProcedure("canManageOwnCanteens")
		.input(createOwnCanteenSchema)
		.mutation(async ({ ctx, input }) => {
			const user = assertAuthenticated(ctx);

			// Only business owners can create new canteens.
			if (!user.businessId) {
				throw new TRPCError({
					code: "FORBIDDEN",
					message: "Only business owners can create new canteens.",
				});
			}

			await ensureUniqueCanteenName(ctx, {
				name: input.name,
				city: input.city,
				businessId: user.businessId,
			});

			// Create the canteen
			const newCanteen = await ctx.db.canteen.create({
				data: {
					name: input.name,
					fullName: input.fullName,
					slug: generateCanteenSlug(input.name, input.city),
					notes: input.notes,
					business: { connect: { id: user.businessId } },
					address: {
						create: {
							street: input.street,
							city: input.city,
							state: input.state,
							zip: input.zip,
							country: input.country,
						},
					},
				},
				include: {
					address: true,
				},
			});

			// Also create a CanteenAccess record for the user (business owner)
			if (!user.id) {
				throw new TRPCError({
					code: "INTERNAL_SERVER_ERROR",
					message: "Authenticated user is missing an id.",
				});
			}
			await ctx.db.canteenAccess.create({
				data: {
					userId: user.id,
					canteenId: newCanteen.id,
				},
			});

			return newCanteen;
		}),

	updateOwn: permissionProcedure("canManageOwnCanteens")
		.input(updateOwnCanteenSchema)
		.mutation(async ({ ctx, input }) => {
			const user = assertAuthenticated(ctx);

			const canteenToUpdate = await ctx.db.canteen.findUnique({
				where: { id: input.id },
			});

			const canUpdate =
				canteenToUpdate && user.canteenAccess?.includes(input.id);

			if (!canUpdate) {
				throw new TRPCError({
					code: "FORBIDDEN",
					message: "You do not have permission to update this canteen.",
				});
			}

			if (input.name && input.city && canteenToUpdate) {
				await ensureUniqueCanteenName(ctx, {
					name: input.name,
					city: input.city,
					businessId: canteenToUpdate.businessId,
					excludeCanteenId: input.id,
				});
			}

			const addressData = {
				street: input.street,
				city: input.city,
				state: input.state,
				zip: input.zip,
				country: input.country,
			};

			const hasAddressData = Object.values(addressData).some((v) => v);

			return ctx.db.canteen.update({
				where: {
					id: input.id,
				},
				data: {
					name: input.name,
					fullName: input.fullName,
					slug:
						input.name && input.city
							? generateCanteenSlug(input.name, input.city)
							: undefined,
					notes: input.notes,
					address: hasAddressData ? { update: addressData } : undefined,
				},
				include: {
					address: true,
				},
			});
		}),

	getOwnById: permissionProcedure("canViewOwnCanteens")
		.input(z.object({ id: z.string().min(1) }))
		.query(async ({ ctx, input }) => {
			const user = assertAuthenticated(ctx);

			const canteen = await ctx.db.canteen.findFirst({
				where: {
					AND: [{ id: input.id }, { id: { in: user.canteenAccess ?? [] } }],
				},
				include: { address: true },
			});

			if (!canteen) {
				throw new TRPCError({
					code: "NOT_FOUND",
					message: "Canteen not found",
				});
			}

			return canteen;
		}),

	deleteOwn: permissionProcedure("canManageOwnCanteens")
		.input(z.object({ id: z.string().min(1) }))
		.mutation(async ({ ctx, input }) => {
			const user = assertAuthenticated(ctx);

			// Find the canteen and check permissions
			const canteen = await ctx.db.canteen.findUnique({
				where: { id: input.id },
			});
			if (!canteen) {
				throw new TRPCError({
					code: "NOT_FOUND",
					message: "Canteen not found",
				});
			}
			const canDelete = user.canteenAccess?.includes(input.id);
			if (!canDelete) {
				throw new TRPCError({
					code: "FORBIDDEN",
					message: "You do not have permission to delete this canteen.",
				});
			}

			// Delete related CanteenAccess records first (to avoid FK errors)
			await ctx.db.canteenAccess.deleteMany({ where: { canteenId: input.id } });
			// Delete the canteen
			await ctx.db.canteen.delete({ where: { id: input.id } });
			return { success: true };
		}),
});