'use client'

import * as React from 'react'
import {
  SvgLineArrowLeftLarge2,
  SvgLineArrowRightLarge2,
  SvgLineArrowExpandWindow1,
  type SvgIcon,
} from '@chainlink/blocks-icons'
import { cn } from '../../utils'
import { Link, type LinkRenderProps } from './Link'

export type TextLinkArrow = 'left' | 'right' | 'external'

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

type BaseTextLinkProps = 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
  /**
   * Adds a directional arrow icon.
   * - `left`: arrow before the text, for back navigation
   * - `right`: arrow after the text, for forward navigation
   * - `external`: expand-window icon after the text, for external links
   */
  arrow?: TextLinkArrow
}

type TextLinkWithAsChild = BaseTextLinkProps & {
  /**
   * Merges TextLink 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 TextLinkWithRenderLink = BaseTextLinkProps & {
  asChild?: never
  /**
   * Render function for framework-specific links.
   * Used internally by blocks components. Mutually exclusive with `asChild`.
   */
  renderLink: RenderLinkFn
}

type TextLinkDefault = BaseTextLinkProps & {
  asChild?: false
  renderLink?: never
}

export type TextLinkProps =
  | TextLinkWithAsChild
  | TextLinkWithRenderLink
  | TextLinkDefault

export type TextLinkArrowProps = SvgIcon & {
  arrow: TextLinkArrow
}

/**
 * Standalone arrow icon used by TextLink. Use directly only when you need to
 * customize the arrow's color or size beyond what the `arrow` prop on
 * TextLink provides. Must be used inside a TextLink or adjacent to link content.
 */
export const TextLinkArrow = ({
  arrow,
  className,
  ...props
}: TextLinkArrowProps) => {
  const baseClassName = 'size-3 shrink-0'
  const combinedClassName = cn(baseClassName, className)

  if (arrow === 'left') {
    return (
      <SvgLineArrowLeftLarge2
        color="currentColor"
        aria-hidden="true"
        className={combinedClassName}
        {...props}
      />
    )
  }

  if (arrow === 'right') {
    return (
      <SvgLineArrowRightLarge2
        color="currentColor"
        aria-hidden="true"
        className={combinedClassName}
        {...props}
      />
    )
  }

  if (arrow === 'external') {
    return (
      <SvgLineArrowExpandWindow1
        color="currentColor"
        aria-hidden="true"
        className={combinedClassName}
        {...props}
      />
    )
  }

  return null
}

/**
 * Styled text link with link color, hover state, and optional directional
 * arrow icons. Renders an `<a>` element and accepts all native anchor
 * attributes. Builds on Link — use Link directly when you need full styling
 * control.
 */
export const TextLink = React.forwardRef<HTMLAnchorElement, TextLinkProps>(
  (
    {
      arrow,
      className,
      children,
      href,
      external,
      newTab,
      asChild,
      renderLink,
      ...props
    },
    ref,
  ) => {
    // Helper to render arrow content with proper positioning
    const renderArrowContent = (childrenContent: React.ReactNode) => (
      <>
        {arrow === 'left' && <TextLinkArrow arrow={arrow} />}
        {childrenContent}
        {(arrow === 'right' || arrow === 'external') && (
          <TextLinkArrow arrow={arrow} />
        )}
      </>
    )

    const content = renderArrowContent(children)

    const linkClassName = cn(
      'hover:text-link-hover inline-flex items-center gap-2 text-link transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring',
      className,
    )

    // Build props for base Link - need to handle the discriminated union properly
    if (asChild) {
      // When using asChild with arrows, we need to clone the child and inject the arrow
      // into its children, so Slot merges props onto the correct element
      const childWithArrow = arrow
        ? React.cloneElement(
            children as React.ReactElement<{ children?: React.ReactNode }>,
            {},
            renderArrowContent(
              (children as React.ReactElement<{ children?: React.ReactNode }>)
                .props.children,
            ),
          )
        : children

      return (
        <Link
          ref={ref}
          href={href}
          external={external}
          newTab={newTab}
          className={linkClassName}
          asChild
          {...props}
        >
          {childWithArrow}
        </Link>
      )
    }

    if (renderLink) {
      return (
        <Link
          ref={ref}
          href={href}
          external={external}
          newTab={newTab}
          className={linkClassName}
          renderLink={renderLink}
          {...props}
        >
          {content}
        </Link>
      )
    }

    return (
      <Link
        ref={ref}
        href={href}
        external={external}
        newTab={newTab}
        className={linkClassName}
        {...props}
      >
        {content}
      </Link>
    )
  },
)

TextLink.displayName = 'TextLink'
