import { useEffect, useState, type ReactNode } from "react";
import { Navigate } from "react-router";
import type { AuthInfo } from "../types";
import { isApiError } from "../api/client";
import DismissibleAlert from "./DismissibleAlert";
import { hasAnyScope, hasScope } from "../utils/permissions";

type PermissionBoundaryProps = {
  auth: AuthInfo;
  anyOf?: string[];
  allOf?: string[];
  fallback: string;
  children: ReactNode;
};

export function PermissionBoundary({ auth, anyOf = [], allOf = [], fallback, children }: PermissionBoundaryProps) {
  if (allOf.length && !allOf.every((scope) => hasScope(auth, scope))) return <Navigate to={fallback} replace />;
  if (anyOf.length && !hasAnyScope(auth, anyOf)) return <Navigate to={fallback} replace />;
  return <>{children}</>;
}

type ResourceAccessBoundaryProps = {
  probe: () => Promise<unknown>;
  resetKey: string;
  fallback: string;
  children: ReactNode;
};

/**
 * Keeps resource routes tenant-agnostic. After a tenant switch the current URL
 * is probed in the new tenant context; inaccessible or missing resources fall
 * back to their parent collection instead of requiring switch-specific routing.
 */
export function ResourceAccessBoundary({ probe, resetKey, fallback, children }: ResourceAccessBoundaryProps) {
  const [state, setState] = useState<"checking" | "allowed" | "denied" | "error">("checking");
  const [message, setMessage] = useState("");

  useEffect(() => {
    let cancelled = false;
    setState("checking");
    setMessage("");
    probe().
    then(() => {if (!cancelled) setState("allowed");}).
    catch((error) => {
      if (cancelled) return;
      if (isApiError(error, 403, 404)) {
        setState("denied");
        return;
      }
      setMessage(error instanceof Error ? error.message : String(error));
      setState("error");
    });
    return () => {cancelled = true;};
  }, [probe, resetKey]);

  if (state === "denied") return <Navigate to={fallback} replace />;
  if (state === "error") return <div className="content-pad"><DismissibleAlert tone="danger" dismissible={false}>{message || "i18n:govoplan-core.the_resource_could_not_be_loaded.0d1b6cbf"}</DismissibleAlert></div>;
  if (state === "checking") return <div className="content-pad"><p className="muted">i18n:govoplan-core.checking_access.c5108c02</p></div>;
  return <>{children}</>;
}
