import { initTRPC } from "@trpc/server";
import { z } from "zod";
import { defineErrorMiddleware } from "@repo/core-shared/trpc/define-error-middleware";

import type { ConsentFactory } from "./di/bind-production";
import { UnauthenticatedError } from "./entities/errors/consent";
import {
  grantHandler,
  grantHandlerInputSchema,
} from "./handlers/grant.handler";
import {
  withdrawHandler,
  withdrawHandlerInputSchema,
} from "./handlers/withdraw.handler";
import {
  isGrantedHandler,
  isGrantedHandlerInputSchema,
} from "./handlers/is-granted.handler";
import { getCategoriesHandler } from "./handlers/get-categories.handler";

/** tRPC context expected by the consent router. */
export type ConsentRouterContext = {
  /** Authenticated user id. Absent → procedures throw UNAUTHORIZED. */
  userId?: string;
  /** Per-user consent factory (provided by the app binder). */
  consentFactory: ConsentFactory;
};

const tc = initTRPC.context<ConsentRouterContext>().create();

const consentProcedure = tc.procedure
  .use(defineErrorMiddleware([[UnauthenticatedError, "UNAUTHORIZED"]]))
  .use(async ({ ctx, next }) => {
    if (!ctx.userId) throw new UnauthenticatedError();
    return next();
  });

export const consentRouter = tc.router({
  grant: consentProcedure
    .input(grantHandlerInputSchema)
    .mutation(async ({ ctx, input }) => {
      const consent = await ctx.consentFactory(ctx.userId!);
      return grantHandler(consent, input);
    }),

  withdraw: consentProcedure
    .input(withdrawHandlerInputSchema)
    .mutation(async ({ ctx, input }) => {
      const consent = await ctx.consentFactory(ctx.userId!);
      return withdrawHandler(consent, input);
    }),

  isGranted: consentProcedure
    .input(isGrantedHandlerInputSchema)
    .query(async ({ ctx, input }) => {
      const consent = await ctx.consentFactory(ctx.userId!);
      return isGrantedHandler(consent, input);
    }),

  getCategories: consentProcedure
    .input(z.object({}).strict())
    .query(async ({ ctx }) => {
      const consent = await ctx.consentFactory(ctx.userId!);
      return getCategoriesHandler(consent);
    }),
});

export type ConsentRouter = typeof consentRouter;
