import React from 'react'
import { Platform, Pressable, StyleSheet, Text } from 'react-native'
import PropTypes from 'prop-types'

import { useThemeTokensCallback } from '../ThemeProvider/useThemeTokens'
import { a11yProps } from '../utils/props/a11yProps'
import { clickProps } from '../utils/props/clickProps'
import { getTokensPropType } from '../utils/props/tokens'
import { linkProps } from '../utils/props/linkProps'
import { resolvePressableTokens } from '../utils/pressability'
import { selectSystemProps } from '../utils/props/selectSystemProps'
import { variantProp } from '../utils/props/variantProp'
import { withLinkRouter } from '../utils/withLinkRouter'

const [selectProps, selectedSystemPropTypes] = selectSystemProps([a11yProps, linkProps])

// ensure explicit selection of tokens
const selectStyles = ({
  backgroundColor,
  outlineColor,
  outlineOffset,
  outlineStyle,
  outlineWidth,
  paddingHorizontal,
  paddingVertical,
  borderRadius
}) => ({
  backgroundColor,
  outlineColor,
  outlineOffset,
  outlineStyle,
  outlineWidth,
  paddingHorizontal,
  paddingVertical,
  borderRadius
})

const selectTextStyles = ({ color, textLine, fontName, fontSize, fontWeight, lineHeight }) => ({
  color,
  textDecorationLine: textLine,
  fontFamily: `${fontName}${fontWeight}normal`,
  lineHeight: fontSize * lineHeight,
  fontSize
})

/**
 * A generic Skip link component, unstyled by default.
 * A Skip link component help keyboard-only users, screen reader users to skip
 * sections and navigate to the content they want.
 *
 * ## Component API
 *
 * For common uses, pass a `href` that is a # link to a DOM id that can be skipped to (web only).
 *
 * The element with this ID should be focusable, e.g. `<Box nativeID="skip-target" focusable>`.
 *
 * Other custom behaviour may be set by passing an `onPress` function, and routers may be integrated
 * in the same way as other navigation-related components by passing a `LinkRouter`; but a # anchor
 * href on web and/or a `targetRef` for cross-platform applications is the recommended approach.
 *
 * ## Visible styling
 *
 * When focused, the skip link shows as a visible element similar to a simplified ButtonLink using
 * UDS theming. The `tokens` prop may be used to override these styles.
 *
 * To control the background of a skip link, the following tokens can be used:
 *
 * - `backgroundColor`
 * *
 * In order to control the color of the skip link text, the following tokens can be used:
 *
 * - `color`
 *
 * ### Padding
 *
 * The following padding tokens can be used:
 *
 * - `paddingHorizontal`
 * - `paddingVertical`
 *
 * ### Outline
 *
 * The following tokens to control the outline:
 *
 * - `outlineColor`
 * - `outlineOffset`
 * - `outlineStyle`
 * - `outlineWidth`
 *
 * ## Usability and A11y guidelines
 *
 * - The skip link component is visually hidden until a keyboard press activates it.
 * - Usually, you should place the skip link immediately after the opening <body> tag.
 * - This lets users bypass top-level navigation links and jump to the main content on a page.
 * - Also consider using SkipLink before a complex feature containing many focusable elements.
 *
 * ## Accessibility
 *
 * Skip link supports all the common a11y and link props.
 */
const SkipLinkBase = React.forwardRef(({ tokens, variant, href, children, ...rawRest }, ref) => {
  const { onPress, ...rest } = clickProps.toPressProps(rawRest)

  const getTokens = useThemeTokensCallback('SkipLink', tokens, variant)

  const handlePress = (event) => {
    if (typeof onPress === 'function') onPress(event)
    // TODO - support native apps with something based on refs and/or setAccessibilityFocus
  }

  return (
    <Pressable
      ref={ref}
      accessibilityRole="link"
      onPress={handlePress}
      href={href}
      style={(pressableState) => {
        const themeTokens = resolvePressableTokens(getTokens, pressableState)
        const skipLinkStyle = selectStyles(themeTokens)
        const { focused } = pressableState
        return [staticStyles.absolute, skipLinkStyle, !focused && staticStyles.hidden]
      }}
      {...selectProps(rest)}
    >
      {(pressableState) => {
        const themeTokens = resolvePressableTokens(getTokens, pressableState)
        const textStyles = selectTextStyles(themeTokens)
        return <Text style={[textStyles, staticStyles.baseline]}>{children}</Text>
      }}
    </Pressable>
  )
})

SkipLinkBase.displayName = 'SkipLink'

SkipLinkBase.propTypes = {
  ...selectedSystemPropTypes,
  /**
   * The text content shown or read out when the SkipLink is focused, usually a string.
   */
  children: PropTypes.node,
  /**
   * The target to skip to. Usually an anchor link to a section id (e.g. href="#main-section").
   */
  href: PropTypes.string,
  tokens: getTokensPropType('SkipLink'),
  variant: variantProp.propType
}

const staticStyles = StyleSheet.create({
  baseline: {
    alignSelf: 'baseline'
  },
  absolute: {
    margin: 0,
    position: 'absolute',
    top: 0,
    left: 0
  },
  hidden: {
    overflow: 'hidden',
    ...Platform.select({
      web: {
        clip: 'rect(0 0 0 0)',
        clipPath: 'inset(50%)'
      },
      default: {
        // width / height of 0 would make it non-focusable
        height: 1,
        width: 1,
        opacity: 0
      }
    })
  }
})

// Export unwrapped component for react-docgen to extract info for docsite
export { SkipLinkBase }

export const SkipLink = withLinkRouter(SkipLinkBase)
