import type { RepositoryContext } from "@/internal/datastore/repository";
import { MemberAccessRolesRepository } from "@/internal/member-access/member-access-roles.repository";
import { MemberAccessRepository } from "@/internal/member-access/member-access.repository";
import type { MemberAccess } from "@/internal/member-access/member-access.services";
import { MemberAccessServices } from "@/internal/member-access/member-access.services";
import { error } from "@/lib/response";
import type { Context, Next } from "hono";

export type MemberCapability =
  | "can_view_analytics"
  | "can_view_bookings"
  | "can_view_sessions"
  | "can_view_activity_logs"
  | "can_view_saved_searches"
  | "can_view_points"
  | "can_reset_password"
  | "can_sync_profile";

/**
 * Resolve the caller's member-module access and stash it on the context.
 *
 * Chain AFTER withConsoleUserSession() (which sets `consoleUserId` and
 * `isAdminConsoleSuperAdmin`) and AFTER the `members` role check: the role grants
 * the module, this decides what inside it the user may touch and which slice of
 * the member base they may see.
 */
export const resolveMemberAccess = async (ctx: Context) => {
  const cached = ctx.get("memberAccess") as MemberAccess | undefined;
  if (cached) return cached;

  const services = MemberAccessServices({
    MemberAccessRepository: MemberAccessRepository(ctx as RepositoryContext),
    // Required: effective access is the union of the user's assigned roles, so
    // GetAccess reads the roles repository. Omitting it threw on every
    // capability check for non-super-admins.
    MemberAccessRolesRepository: MemberAccessRolesRepository(
      ctx as RepositoryContext,
    ),
  });
  const access = await services.GetAccess(
    String(ctx.get("consoleUserId") ?? ""),
    Boolean(ctx.get("isAdminConsoleSuperAdmin")),
  );
  ctx.set("memberAccess", access);
  return access;
};

/** Requires one capability inside the member module. */
export const withMemberAccess =
  (capability: MemberCapability) => async (ctx: Context, next: Next) => {
    const access = await resolveMemberAccess(ctx);
    if (!access[capability]) {
      return error(
        ctx,
        "You do not have access to this part of the member module",
        403,
      );
    }
    await next();
  };

/** Makes the resolved access available without requiring any capability. */
export const withResolvedMemberAccess =
  () => async (ctx: Context, next: Next) => {
    await resolveMemberAccess(ctx);
    await next();
  };
