import React from 'react';
import { Navigate, useLocation, Outlet } from 'react-router';
import { useAppDispatch, useAppSelector } from '@/store/hooks';
import { fetchCurrentUser, markInitialized } from '@/store/slices/authSlice';
import {
  hasPermission,
  resolveDefaultAuthorizedPath,
  resolveRequiredPermissionByPath,
} from '@/auth/permissions';

interface ProtectedRouteProps {
  children?: React.ReactNode;
}

const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
  const dispatch = useAppDispatch();
  const { isAuthenticated, token, initialized, loading, permissions } = useAppSelector(
    (state) => state.auth
  );
  const location = useLocation();
  const requiredPermission = resolveRequiredPermissionByPath(location.pathname);

  React.useEffect(() => {
    if (initialized || loading) {
      return;
    }
    if (!token) {
      dispatch(markInitialized());
      return;
    }
    void dispatch(fetchCurrentUser());
  }, [dispatch, initialized, loading, token]);

  if (!initialized || loading) {
    return null;
  }

  if (!isAuthenticated) {
    // Redirect to the login page, but save the current location they were trying to go to
    return <Navigate to="/login" state={{ from: location }} replace />;
  }

  if (!hasPermission(permissions, requiredPermission)) {
    const fallbackPath = resolveDefaultAuthorizedPath(permissions);
    if (location.pathname === fallbackPath) {
      return <Navigate to="/403" replace />;
    }
    return <Navigate to={fallbackPath} replace />;
  }

  return children ? <>{children}</> : <Outlet />;
};

export default ProtectedRoute;
