// lib/createProtectedLoader.ts
import { redirect, type LoaderFunctionArgs } from "react-router";
import { adminSignout } from "./auth/action";
import { checkAccess } from "../role-helpers";
import type { RolePrivilegeType } from "./types";

export const UNAUTHORIZED = Symbol("UNAUTHORIZED");

async function handleUnauthorized(request?: Request) {
  try {
    if (request) {
      const logoutRes = await adminSignout(request);
      if (logoutRes.success) {
        const setCookieHeaders = (
          logoutRes.data as Response
        ).headers.getSetCookie();
        throw redirect("/auth/signin", {
          headers: new Headers(
            // @ts-ignore
            setCookieHeaders?.map((cookie) => ["Set-Cookie", cookie]),
          ),
        });
      }
    }
  } catch (err) {
    if (err instanceof Response) throw err;
  }
  throw redirect("/auth/signin");
}

export function createProtectedLoader<T>(
  loaderFn: (args: LoaderFunctionArgs) => Promise<T>,
) {
  return async (args: LoaderFunctionArgs): Promise<T> => {
    try {
      const result = await loaderFn(args);
      if (result === UNAUTHORIZED) {
        await handleUnauthorized(args.request);
      }

      // Handle object responses where any value is UNAUTHORIZED
      if (result && typeof result === "object") {
        const hasUnauthorized = Object.values(result).some(
          (value) => value === UNAUTHORIZED,
        );
        if (hasUnauthorized) {
          await handleUnauthorized(args.request);
        }
      }

      return result;
    } catch (err) {
      if (err === UNAUTHORIZED) {
        await handleUnauthorized(args.request);
      }
      throw err;
    }
  };
}

export function createRoleProtectedLoader<T>(
  featureSlug: string,
  privilegeType: RolePrivilegeType,
  loaderFn: (args: LoaderFunctionArgs) => Promise<T>,
) {
  return createProtectedLoader(async (args) => {
    const hasAccess = checkAccess(args.request, privilegeType, featureSlug);
    if (!hasAccess) {
      throw redirect("/admin/dashboard");
    }
    return loaderFn(args);
  });
}
