import React from 'react'
import {
  DURATION,
  SVG_CIRCUMFERENCE,
  SVG_SIZE,
  ROTATION_TRANSFORM,
  SVG_CENTER,
  SPINNER_RADIUS,
  SPINNER_ROTATION_DEGREES,
  SPINNER_DASHARRAY_MIN,
  SPINNER_DASHARRAY_MAX,
  SPINNER_KEYTIMES,
  SPINNER_DASHARRAY_HALF,
  SPINNER_DASHOFFSET_FACTOR,
  propTypes
} from './shared'
import { useA11yInfo } from '../A11yInfoProvider/A11yInfoProvider'

const animateProps = {
  keyTimes: SPINNER_KEYTIMES,
  repeatCount: 'indefinite'
}

export const Spinner = React.forwardRef(
  ({ size, color, indicatorBackgroundColor, thickness, label, isStatic = false }, ref) => {
    const { reduceMotionEnabled } = useA11yInfo()
    const reduceMotion = reduceMotionEnabled || isStatic

    const strokeWidth = (thickness * SVG_SIZE) / size

    return (
      <svg
        ref={ref}
        width={`${size}px`}
        height={`${size}px`}
        viewBox={`0 0 ${SVG_SIZE} ${SVG_SIZE}`}
        aria-valuetext={label}
        role="progressbar"
        aria-busy="true"
      >
        {/* Base static circle with background color */}
        <circle
          fill="none"
          stroke={indicatorBackgroundColor}
          strokeWidth={strokeWidth}
          cx={SVG_CENTER}
          cy={SVG_CENTER}
          r={SPINNER_RADIUS}
        />

        {/* Animated circle */}
        <circle
          fill="none"
          stroke={color}
          strokeWidth={strokeWidth}
          strokeLinecap="round"
          cx={SVG_CENTER}
          cy={SVG_CENTER}
          r={SPINNER_RADIUS}
          strokeDasharray={`${SPINNER_DASHARRAY_MIN * SVG_CIRCUMFERENCE}, ${
            SPINNER_DASHARRAY_MAX * SVG_CIRCUMFERENCE
          }`}
          strokeDashoffset="0"
          // Circle rotated -90° so that 0% is at the top (12 o'clock).
          transform={ROTATION_TRANSFORM}
        >
          {reduceMotion ? null : (
            <>
              {/*
                Rotation animated from 0° to 183°, 
                with additive="sum" is added to the base rotation of -90°.
              */}
              <animateTransform
                attributeName="transform"
                type="rotate"
                from="0 24 24"
                to={`${SPINNER_ROTATION_DEGREES} ${SVG_CENTER} ${SVG_CENTER}`}
                dur={`${DURATION}ms`}
                repeatCount="indefinite"
                additive="sum"
              />
              <animate
                attributeName="stroke-dasharray"
                dur={`${DURATION}ms`}
                values={`
                  ${SPINNER_DASHARRAY_MIN * SVG_CIRCUMFERENCE},${
                  SPINNER_DASHARRAY_MAX * SVG_CIRCUMFERENCE
                };
                  ${SPINNER_DASHARRAY_HALF * SVG_CIRCUMFERENCE},${
                  SPINNER_DASHARRAY_HALF * SVG_CIRCUMFERENCE
                };
                  ${SPINNER_DASHARRAY_MIN * SVG_CIRCUMFERENCE},${
                  SPINNER_DASHARRAY_MAX * SVG_CIRCUMFERENCE
                }
                `}
                {...animateProps}
              />
              <animate
                attributeName="stroke-dashoffset"
                dur={`${DURATION}ms`}
                values={`
                  0;
                  0;
                  -${SPINNER_DASHOFFSET_FACTOR * SVG_CIRCUMFERENCE}
                `}
                {...animateProps}
              />
            </>
          )}
        </circle>
      </svg>
    )
  }
)

Spinner.displayName = 'Spinner'
Spinner.propTypes = propTypes
