'use client'

import { Slot } from '@radix-ui/react-slot'
import * as React from 'react'
import { cn } from '../../utils'

export type LinkRenderProps = React.AnchorHTMLAttributes<HTMLAnchorElement> & {
  href: string
  children: React.ReactNode
}

type RenderLinkFn = (props: LinkRenderProps) => React.ReactNode

type BaseLinkProps = Omit<
  React.AnchorHTMLAttributes<HTMLAnchorElement>,
  'href'
> & {
  /** The URL the link points to. Required. */
  href: string
  /**
   * Adds `rel="noopener noreferrer"` for security.
   * Use for all links pointing to external sites.
   */
  external?: boolean
  /**
   * Opens the link in a new browser tab (`target="_blank"`).
   */
  newTab?: boolean
}

type LinkWithAsChild = BaseLinkProps & {
  /**
   * Merges Link props onto a child element via Radix Slot.
   * Use to compose with framework-specific link components (e.g. Next.js Link).
   * Mutually exclusive with `renderLink`.
   */
  asChild: true
  renderLink?: never
}

type LinkWithRenderLink = BaseLinkProps & {
  asChild?: never
  /**
   * Render function for framework-specific links.
   * Used internally by blocks components for framework-agnostic navigation.
   * Mutually exclusive with `asChild`.
   */
  renderLink: RenderLinkFn
}

type LinkDefault = BaseLinkProps & {
  asChild?: false
  renderLink?: never
}

export type LinkProps = LinkWithAsChild | LinkWithRenderLink | LinkDefault

/**
 * Unstyled base component for navigation links. Renders an `<a>` element and
 * accepts all native anchor attributes. Use `asChild` to compose with
 * framework-specific link components (e.g. Next.js Link). For styled inline
 * text links, use TextLink instead.
 */
export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
  (
    {
      href,
      asChild,
      renderLink,
      external = false,
      newTab = false,
      className,
      children,
      rel,
      target,
      ...props
    },
    ref,
  ) => {
    // Compute rel attribute
    const computedRel = external ? cn(rel, 'noopener noreferrer') : rel

    // Compute target attribute
    const computedTarget = newTab ? '_blank' : target

    const linkProps = {
      href,
      rel: computedRel || undefined,
      target: computedTarget,
      className,
      ...props,
    }

    // Priority 1: asChild - use Slot to merge props onto child
    if (asChild) {
      return (
        <Slot ref={ref} {...linkProps}>
          {children}
        </Slot>
      )
    }

    // Priority 2: renderLink - call function to create element
    if (renderLink) {
      return <>{renderLink({ ...linkProps, children })}</>
    }

    // Default: plain anchor
    return (
      <a ref={ref} {...linkProps}>
        {children}
      </a>
    )
  },
)

Link.displayName = 'Link'
