/**
 * Protected Route component for handling authentication and authorization
 */

import React from 'react';
import { Navigate, useLocation } from 'react-router-dom';
import { useAuthUser, useIsAuthenticated, useAuthLoading } from '../stores';
import { RouteConfig, canAccessRoute, ROUTES } from './routes.config';

interface ProtectedRouteProps {
  children: React.ReactNode;
  route?: RouteConfig;
  fallback?: React.ReactNode;
  redirectTo?: string;
}

interface LoadingSpinnerProps {
  message?: string;
}

const LoadingSpinner: React.FC<LoadingSpinnerProps> = ({ message = 'Cargando...' }) => (
  <div className="flex items-center justify-center min-h-screen bg-bg-primary">
    <div className="flex flex-col items-center gap-4">
      <div className="spinner spinner-lg"></div>
      <p className="text-text-secondary text-sm">{message}</p>
    </div>
  </div>
);

const UnauthorizedPage: React.FC = () => (
  <div className="flex items-center justify-center min-h-screen bg-bg-primary">
    <div className="text-center max-w-md mx-auto px-6">
      <div className="mb-6">
        <div className="w-16 h-16 mx-auto mb-4 bg-color-error rounded-full flex items-center justify-center">
          <svg 
            className="w-8 h-8 text-text-inverse" 
            fill="none" 
            stroke="currentColor" 
            viewBox="0 0 24 24"
          >
            <path 
              strokeLinecap="round" 
              strokeLinejoin="round" 
              strokeWidth={2} 
              d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L4.732 19.5c-.77.833.192 2.5 1.732 2.5z" 
            />
          </svg>
        </div>
        <h1 className="text-2xl font-bold text-text-primary mb-2">
          Acceso no autorizado
        </h1>
        <p className="text-text-secondary mb-6">
          No tienes permisos para acceder a esta página. Contacta con tu administrador si crees que esto es un error.
        </p>
      </div>
      
      <div className="flex flex-col gap-3">
        <button
          onClick={() => window.history.back()}
          className="btn btn-primary"
        >
          Volver atrás
        </button>
        <button
          onClick={() => window.location.href = ROUTES.DASHBOARD}
          className="btn btn-outline"
        >
          Ir al Panel de Control
        </button>
      </div>
    </div>
  </div>
);

const ForbiddenPage: React.FC = () => (
  <div className="flex items-center justify-center min-h-screen bg-bg-primary">
    <div className="text-center max-w-md mx-auto px-6">
      <div className="mb-6">
        <div className="w-16 h-16 mx-auto mb-4 bg-color-warning rounded-full flex items-center justify-center">
          <svg 
            className="w-8 h-8 text-text-inverse" 
            fill="none" 
            stroke="currentColor" 
            viewBox="0 0 24 24"
          >
            <path 
              strokeLinecap="round" 
              strokeLinejoin="round" 
              strokeWidth={2} 
              d="M18.364 18.364A9 9 0 005.636 5.636m12.728 12.728L5.636 5.636m12.728 12.728L5.636 5.636" 
            />
          </svg>
        </div>
        <h1 className="text-2xl font-bold text-text-primary mb-2">
          Acceso restringido
        </h1>
        <p className="text-text-secondary mb-6">
          Tu cuenta no tiene los permisos necesarios para ver esta sección. Contacta con tu administrador para solicitar acceso.
        </p>
      </div>
      
      <div className="flex flex-col gap-3">
        <button
          onClick={() => window.history.back()}
          className="btn btn-primary"
        >
          Volver atrás
        </button>
        <button
          onClick={() => window.location.href = ROUTES.DASHBOARD}
          className="btn btn-outline"
        >
          Ir al Panel de Control
        </button>
      </div>
    </div>
  </div>
);

export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
  children,
  route,
  fallback,
  redirectTo,
}) => {
  const user = useAuthUser();
  const isAuthenticated = useIsAuthenticated();
  const isLoading = useAuthLoading();
  const location = useLocation();

  // Show loading spinner while checking authentication
  if (isLoading) {
    return fallback || <LoadingSpinner message="Verificando autenticación..." />;
  }

  // If route doesn't require auth, render children
  if (route && !route.requiresAuth) {
    return <>{children}</>;
  }

  // If not authenticated and route requires auth, redirect to login
  if (!isAuthenticated) {
    const redirectPath = redirectTo || ROUTES.LOGIN;
    const returnUrl = location.pathname + location.search;
    
    return (
      <Navigate 
        to={`${redirectPath}?returnUrl=${encodeURIComponent(returnUrl)}`} 
        replace 
      />
    );
  }

  // If no route config is provided, just check authentication
  if (!route) {
    return <>{children}</>;
  }

  // Get user roles and permissions
  const userRoles = user?.role ? [user.role] : [];
  const userPermissions: string[] = [];

  // Check if user can access this route
  const canAccess = canAccessRoute(route, isAuthenticated, userRoles, userPermissions);

  if (!canAccess) {
    // Check if it's a permission issue or role issue
    const hasRequiredRoles = !route.requiredRoles || 
      route.requiredRoles.some(role => userRoles.includes(role));
    
    if (!hasRequiredRoles) {
      return <UnauthorizedPage />;
    } else {
      return <ForbiddenPage />;
    }
  }

  // User has access, render the protected content
  return <>{children}</>;
};

// Higher-order component for route protection
export const withProtectedRoute = <P extends object>(
  Component: React.ComponentType<P>,
  route: RouteConfig,
  options?: {
    fallback?: React.ReactNode;
    redirectTo?: string;
  }
) => {
  const ProtectedComponent = (props: P) => (
    <ProtectedRoute 
      route={route} 
      fallback={options?.fallback}
      redirectTo={options?.redirectTo}
    >
      <Component {...props} />
    </ProtectedRoute>
  );

  ProtectedComponent.displayName = `withProtectedRoute(${Component.displayName || Component.name})`;
  
  return ProtectedComponent;
};

// Hook for checking route access
export const useRouteAccess = (route: RouteConfig) => {
  const user = useAuthUser();
  const isAuthenticated = useIsAuthenticated();
  const isLoading = useAuthLoading();

  const userRoles = user?.role ? [user.role] : [];
  const userPermissions: string[] = [];

  const canAccess = canAccessRoute(route, isAuthenticated, userRoles, userPermissions);

  return {
    canAccess,
    isLoading,
    isAuthenticated,
    userRoles,
    userPermissions,
    hasRequiredRoles: !route.requiredRoles || 
      route.requiredRoles.some(role => userRoles.includes(role)),
    hasRequiredPermissions: !route.requiredPermissions || 
      route.requiredPermissions.every(permission => userPermissions.includes(permission)),
  };
};

// Component for conditionally rendering content based on permissions
interface ConditionalRenderProps {
  children: React.ReactNode;
  requiredPermissions?: string[];
  requiredRoles?: string[];
  requireAll?: boolean; // If true, requires ALL permissions/roles, otherwise ANY
  fallback?: React.ReactNode;
}

export const ConditionalRender: React.FC<ConditionalRenderProps> = ({
  children,
  requiredPermissions = [],
  requiredRoles = [],
  requireAll = true,
  fallback = null,
}) => {
  const user = useAuthUser();
  const isAuthenticated = useIsAuthenticated();

  if (!isAuthenticated || !user) {
    return <>{fallback}</>;
  }

  const userRoles = user.role ? [user.role] : [];
  const userPermissions: string[] = [];

  // Check roles
  let hasRoles = true;
  if (requiredRoles.length > 0) {
    if (requireAll) {
      hasRoles = requiredRoles.every(role => userRoles.includes(role));
    } else {
      hasRoles = requiredRoles.some(role => userRoles.includes(role));
    }
  }

  // Check permissions
  let hasPermissions = true;
  if (requiredPermissions.length > 0) {
    if (requireAll) {
      hasPermissions = requiredPermissions.every(permission => userPermissions.includes(permission));
    } else {
      hasPermissions = requiredPermissions.some(permission => userPermissions.includes(permission));
    }
  }

  if (hasRoles && hasPermissions) {
    return <>{children}</>;
  }

  return <>{fallback}</>;
};

// Route guard for admin-only routes
export const AdminRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  return (
    <ConditionalRender
      requiredRoles={['admin', 'super_admin']}
      requireAll={false}
      fallback={<UnauthorizedPage />}
    >
      {children}
    </ConditionalRender>
  );
};

// Route guard for manager-level routes
export const ManagerRoute: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  return (
    <ConditionalRender
      requiredRoles={['admin', 'super_admin', 'manager']}
      requireAll={false}
      fallback={<UnauthorizedPage />}
    >
      {children}
    </ConditionalRender>
  );
};