import { useEffect, useMemo, type ComponentType, type ReactNode } from 'react'
import type { LucideIcon } from 'lucide-react'
import type { Identifier, ResourceDefinition } from '../types'
import { ResourceProvider } from '../context/resource-context'
import { useResources } from '../context/resource-context'

export interface ResourceProps {
  /** Resource identifier used in URLs and data provider calls */
  name: string
  /** Human-readable singular label */
  label?: string
  /** Human-readable plural label */
  labelPlural?: string
  /** Icon component for navigation */
  icon?: LucideIcon
  /** Component to render the list view */
  list?: ComponentType
  /** Component to render the show/detail view */
  show?: ComponentType<{ id: Identifier }>
  /** Component to render the create view */
  create?: ComponentType
  /** Component to render the edit view */
  edit?: ComponentType<{ id: Identifier }>
  /** Custom options for this resource */
  options?: Record<string, unknown>
  /** Children to render (optional - for custom resource rendering) */
  children?: ReactNode
}

/**
 * Resource component for registering and configuring CRUD resources.
 *
 * Resources are automatically registered with the ResourcesProvider when mounted,
 * and unregistered when unmounted. This allows for dynamic resource registration
 * in your application.
 *
 * **Usage Patterns:**
 *
 * 1. **Declarative Registration** - Use Resource components inside App
 * 2. **Programmatic Registration** - Pass resources array to App
 * 3. **Router Integration** - Use with your router
 *
 * @example
 * ```tsx
 * // Declarative registration
 * <App dataProvider={myDataProvider} authProvider={myAuthProvider}>
 *   <Resource
 *     name="users"
 *     label="User"
 *     labelPlural="Users"
 *     icon={Users}
 *     list={UsersList}
 *     show={UserShow}
 *     create={UserCreate}
 *     edit={UserEdit}
 *   />
 *   <Resource
 *     name="products"
 *     label="Product"
 *     labelPlural="Products"
 *     icon={Package}
 *     list={ProductsList}
 *   />
 * </App>
 * ```
 */
export function Resource({
  name,
  label,
  labelPlural,
  icon,
  list,
  show,
  create,
  edit,
  options,
  children,
}: ResourceProps) {
  const { registerResource, unregisterResource } = useResources()

  // Build memoized resource definition to avoid unnecessary re-registrations
  // Only recreate when any of the resource properties change
  const definition = useMemo<ResourceDefinition>(() => ({
    name,
    label,
    labelPlural,
    icon,
    list,
    show,
    create,
    edit,
    options,
  }), [name, label, labelPlural, icon, list, show, create, edit, options])

  // Register when definition changes, unregister on unmount
  useEffect(() => {
    registerResource(definition)
    return () => unregisterResource(name)
  }, [definition, name, registerResource, unregisterResource])

  // If children are provided, wrap them in ResourceProvider
  if (children) {
    return (
      <ResourceProvider resource={name} definition={definition}>
        {children}
      </ResourceProvider>
    )
  }

  // If no children, just return null (resource is registered via useEffect)
  return null
}

/**
 * Higher-order component to wrap a view component with resource context.
 *
 * @example
 * ```tsx
 * const UsersListWithContext = withResource(UsersList, {
 *   name: 'users',
 *   label: 'Users',
 * })
 * ```
 */
export function withResource<P extends object>(
  WrappedComponent: ComponentType<P>,
  resourceDef: ResourceDefinition
) {
  function WithResource(props: P) {
    return (
      <ResourceProvider resource={resourceDef.name} definition={resourceDef}>
        <WrappedComponent {...props} />
      </ResourceProvider>
    )
  }

  WithResource.displayName = `withResource(${WrappedComponent.displayName ?? WrappedComponent.name ?? 'Component'})`
  return WithResource
}
